home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevamiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  114.6 KB  |  5,345 lines

  1. /* Copyright (C) 1992, 1995 Aladdin Enterprises.  All rights reserved.
  2.  
  3.   This file is part of Aladdin Ghostscript.
  4.  
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.  
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevamiga.c */
  20. /* Amiga driver for Ghostscript library, requires Kickstart 2.04 or higher */
  21.  
  22. /* Original development and maintenance up to and including gs3.5.3:
  23.  *
  24.  *    Olaf 'Olsen' Barthel
  25.  *
  26.  *    Address:    Olaf Barthel
  27.  *                Brabeckstrasse 35
  28.  *                D-30559 Hannover
  29.  *    Internet:    olsen@sourcery.han.de
  30.  *
  31.  *
  32.  * Current maintenance, libnix integration and 'autoconfiscation':
  33.  *
  34.  *    Joop van de Wege
  35.  *
  36.  *    Internet:    JoopvandeWege@mail.mococo.nl
  37.  *
  38.  *
  39.  * Revised device/size/resolution handling:
  40.  *
  41.  *    Steffen Opel
  42.  *
  43.  *    Internet:   opel@rumms.uni-mannheim.de
  44.  *
  45.  *
  46.  * Couple of changes to compile it with Ghostscript 6.50, PPC
  47.  * changes - note that for PPC I don't call Forbid/Permit but
  48.  * use a global variable because I got crashes otherwise?!?
  49.  *
  50.  * RĂ¼diger Hanke
  51.  *
  52.  * Internet: tomjoad@muenster.de
  53.  */
  54.  
  55. #include <clib/alib_protos.h>
  56. #include <clib/macros.h>
  57. #include <datatypes/pictureclass.h>
  58. #include <dos/dostags.h>
  59. #include <dos/rdargs.h>
  60. #include <dos/var.h>
  61. #include <dos/dos.h>
  62. #include <devices/printer.h>
  63. #include <devices/prtbase.h>
  64. #include <devices/prtgfx.h>
  65. #include <exec/errors.h>
  66. #include <exec/memory.h>
  67. #include <graphics/displayinfo.h>
  68. #include <graphics/gfxbase.h>
  69. #include <intuition/intuitionbase.h>
  70. #include <intuition/gadgetclass.h>
  71. #include <intuition/imageclass.h>
  72. #include <intuition/icclass.h>
  73. #include <libraries/asl.h>
  74. #include <libraries/iffparse.h>
  75.  
  76. #include <proto/asl.h>
  77. #include <proto/dos.h>
  78. #include <proto/exec.h>
  79. #include <proto/graphics.h>
  80. #include <proto/iffparse.h>
  81. #include <proto/intuition.h>
  82. #include <proto/layers.h>
  83. #include <proto/utility.h>
  84.  
  85. #ifdef __PPC__
  86. #include <proto/powerpc.h>
  87. #include <powerpc/tasksPPC.h>
  88. #endif
  89.  
  90. #include "gscdefs.h"
  91. #include "gserrors.h"
  92. #include "gx.h"        /* for gx_bitmap; includes std.h */
  93. #include "gxdevice.h"
  94. #include "gxfixed.h"    /* needed for amiga_put_params only */
  95. #include "gsparam.h"
  96.  
  97. #include <string.h>
  98. #include <signal.h>
  99.  
  100. #ifdef __STORMGCC__
  101. typedef unsigned int sigset_t;
  102. #define sigmask(m)    (1 << ((m)-1))
  103. #endif
  104.  
  105. #ifdef __PPC__
  106. gx_device *DispatchTaskDevice;
  107. #endif
  108.  
  109.  
  110.     /* Magic value to compute the resolution from the display database.
  111.      *
  112.      * To compute the dots_per_inch resolution from the ticks_per_pixel 
  113.      * resolution in the display database the common base is needed. 
  114.      * These base ensures that all Display Modes will be displayed with 
  115.      * the same absolute aspect ratio. Don't ask me how the ticks_per_pixel 
  116.      * entries are computed exactly, the supplied value has been determined 
  117.      * with respect to GfxBase->NormalDisplay[Rows|Columns], some monitors
  118.      * and a meter. Therefore it may be fine tuned to fit any specific 
  119.      * monitor/gfx-board environment.
  120.      *
  121.      * TODO: Resolve the constitutional calculation for those entries
  122.      * in the display database!
  123.      */
  124.  
  125. #define MAGIC_DPI_BASE_VALUE    1447
  126.  
  127.     /* Initial values for resolution and size. */
  128.  
  129. #define INITIAL_X_DPI        72
  130. #define INITIAL_Y_DPI        72
  131.  
  132. #ifdef A4
  133. /* A4 paper (210mm x 297mm).  The dimensions are off by a few nm.... */
  134. #define INITIAL_WIDTH        (int)(8.27 * INITIAL_X_DPI)
  135. #define INITIAL_HEIGHT        (int)(11.7 * INITIAL_Y_DPI)
  136. #else
  137. /* U.S. letter paper (8.5" x 11"). */
  138. #define INITIAL_WIDTH        (int)(8.5 * INITIAL_X_DPI)
  139. #define INITIAL_HEIGHT        (int)(11.0 * INITIAL_Y_DPI)
  140. #endif
  141.  
  142.     /* Default Display Mode. */
  143.  
  144. #define DEFAULT_DISPLAYMODE    ""
  145.  
  146.     /* Default output file name. */
  147.  
  148. #define DEFAULT_FILENAME    "gs_page"
  149.  
  150.     /* Turn a byte into a 24 bit colour value. */
  151.  
  152. #define SPREAD(i)    ((ULONG)(i) << 24 | (ULONG)(i) << 16 | (ULONG)(i) << 8 | (i))
  153.  
  154.     /* Scroller gadget IDs. */
  155.  
  156. enum    {    VERTICAL_SCROLLER,    HORIZONTAL_SCROLLER,
  157.         UP_ARROW,        DOWN_ARROW,
  158.         LEFT_ARROW,        RIGHT_ARROW,
  159.  
  160.         GADGET_COUNT
  161.     };
  162.  
  163.     /* Scroller arrow IDs. */
  164.  
  165. enum    {    UP_IMAGE,        DOWN_IMAGE,
  166.         LEFT_IMAGE,        RIGHT_IMAGE,
  167.  
  168.         IMAGE_COUNT
  169.     };
  170.  
  171.     /* Codes for the MoveAround() routine. */
  172.  
  173. enum    {    MOVE_MIN,MOVE_FAR_DOWN,MOVE_DOWN,MOVE_UP,MOVE_FAR_UP,MOVE_MAX };
  174.  
  175.     /* Some handy bit masks. */
  176.  
  177. #define SIG_KILL    SIGBREAKF_CTRL_C
  178. #define SIG_HANDSHAKE    SIGF_SINGLE
  179. #define SIG_WAKEUP    SIGBREAKF_CTRL_E
  180.  
  181.     /* Static dimensions of scroller arrows. */
  182.  
  183. #define ARROW_WIDTH    16
  184. #define ARROW_HEIGHT    11
  185.  
  186.     /* The `Help' key raw code. */
  187.  
  188. #define HELP_CODE    95
  189.  
  190.     /* Minimum window inner area dimension. */
  191.  
  192. #define MINIMUM_WIDTH    64
  193. #define MINIMUM_HEIGHT    32
  194.  
  195.     /* Handy superbitmap window macros. */
  196.  
  197. #define LAYERXOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_X)
  198. #define LAYERYOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_Y)
  199.  
  200.     /* User input to listen to. */
  201.  
  202. #define IDCMP_FLAGS    (IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY)
  203.  
  204.     /* Chunk IDs. */
  205.  
  206. #define ID_ANNO        MAKE_ID('A','N','N','O')
  207. #define ID_DPI        MAKE_ID('D','P','I',' ')
  208.  
  209. typedef struct
  210. {
  211.     UWORD        dpi_x;
  212.     UWORD        dpi_y;
  213. } DPIHeader;
  214.  
  215.     /* Packer modes. */
  216.  
  217. #define DUMP        0
  218. #define RUN        1
  219.  
  220.     /* Minimum data run size, maximum data run size and maximum cache size. */
  221.  
  222. #define MINRUN        3
  223. #define MAXRUN        128
  224. #define MAXDAT        128
  225.  
  226.     /* This module actually implements four different Amiga based
  227.      * devices. As the rendering operations are all the same,
  228.      * one single device definition is sufficient.
  229.      */
  230.  
  231. typedef struct gx_device_amiga
  232. {
  233.     gx_device_common;
  234.  
  235.     struct Screen    *screen;    /* Any screen */
  236.     struct Window    *window;    /* Some window to be opened on the Workbench screen */
  237.  
  238.     struct BitMap    *super_bitmap;    /* Window superbitmap area */
  239.     struct Gadget    **gadget;    /* Scroller gadgets */
  240.     struct Image    **image;    /* Scroller arrow images */
  241.  
  242.     struct Task    *dispatcher;    /* Slider dispatch task */
  243.     struct Process    *main;        /* Main program */
  244.  
  245.     struct RastPort    *rport;        /* Rendering area */
  246.  
  247.     struct IODRPReq *printer;    /* Printer interface data */
  248.     struct MsgPort    *port;        /* Printer io data */
  249.  
  250.     struct ColorMap    *colormap;    /* A black/white colour map */
  251.     struct BitMap    *bitmap;    /* Rendering bitmap data */
  252.     PLANEPTR     bitplane;    /* Rendering raster */
  253.  
  254.     gx_color_index     last_pen;    /* The last colour set */
  255.  
  256.     char        display_mode[DISPLAYNAMELEN + 1];    /* The Display Mode */
  257.     char        file_name[256];/* The output file name */
  258.     int         page_count;    /* The page number counter */
  259.  
  260.     int         cube_size;    /* Colour cube size, 0 for b/w */
  261.     struct RastPort    *temp_rport;    /* Temporary raster port for pixmap imaging. */
  262.     UBYTE        *temp_array;    /* Temporary colour manipulation array. */
  263.     LONG        *pens;
  264. } gx_device_amiga;
  265.  
  266.     /* Cheap, but effective macro for casting the device argument ;-) */
  267.  
  268. #define xdev ((gx_device_amiga *)dev)
  269.  
  270.     /* Support functions */
  271.  
  272. private int amiga_open(gx_device *dev, ULONG Mode);
  273. private VOID set_mono_device(gx_device_amiga *dev);
  274. private VOID set_colour_device(gx_device_amiga *dev, int cube_size, 
  275.     LONG *pens);
  276. private VOID set_colour_printer_device(gx_device_amiga *dev, LONG CubeSize);
  277. private LONG * AllocatePens(struct ViewPort *VPort, LONG CubeSize);
  278. private VOID DeleteBitMap(struct BitMap *BitMap, BOOL Private);
  279. private struct BitMap * CreateBitMap(LONG Width, LONG Height, LONG Depth, 
  280.     ULONG Flags, struct BitMap *Friend, BOOL Private);
  281. private VOID DeleteTempRPort(struct RastPort *Temp);
  282. private struct RastPort * CreateTempRPort(struct RastPort *Source);
  283. private LONG Euclid(LONG a, LONG b);
  284. private BYTE * PutDump(register BYTE *Destination, register LONG Count);
  285. private BYTE * PutRun(register BYTE *Destination, LONG Count, WORD Char);
  286. private LONG PackRow(PLANEPTR *SourcePtr, register BYTE *Destination, 
  287.     LONG RowSize);
  288. private BOOL PutBODY(struct IFFHandle *Handle, struct BitMap *BitMap);
  289. private BOOL PutANNO(struct IFFHandle *Handle);
  290. private BOOL PutCAMG(struct IFFHandle *Handle);
  291. private BOOL PutCMAP(struct IFFHandle *Handle);
  292. private BOOL PutDPI(struct IFFHandle *Handle, UWORD X_DPI, UWORD Y_DPI);
  293. private BOOL PutBMHD(struct IFFHandle *Handle, LONG Width, LONG Height, 
  294.     UWORD X_DPI, UWORD Y_DPI);
  295. private BOOL SaveBitMap(STRPTR Name, struct BitMap *BitMap, LONG Width, 
  296.     LONG Height, UWORD X_DPI, UWORD Y_DPI);
  297. private VOID DispatchTask(VOID);
  298. private VOID DeleteScrollers(gx_device *dev);
  299. private BOOL CreateScrollers(gx_device *dev, struct Screen *Screen);
  300. private VOID WindowResize(gx_device *dev);
  301. private VOID WindowUpdate(struct Gadget *Gadget, gx_device *dev);
  302. private VOID MoveAround(struct Gadget *Gadget, LONG How, gx_device *dev);
  303. private VOID DispatchSuperWindow(gx_device *dev);
  304. private VOID PrintPrinterError(const char *header, LONG io_Error);
  305. void devcleanup(VOID);
  306.  
  307.     /* Device procedures (see gxdevice.h for the definitions) */
  308.  
  309. private dev_proc_open_device(amiga_open_default);
  310. private dev_proc_open_device(amiga_open_custom);
  311. private dev_proc_open_device(amiga_open_printer);
  312. private dev_proc_open_device(amiga_open_ilbm);
  313. private dev_proc_output_page(amiga_output_page);
  314. private dev_proc_output_page(amiga_output_page_printer);
  315. private dev_proc_output_page(amiga_output_page_ilbm);
  316. private dev_proc_close_device(amiga_close);
  317. private dev_proc_close_device(amiga_close_printer);
  318. private dev_proc_close_device(amiga_close_ilbm);
  319. private dev_proc_map_rgb_color(amiga_map_rgb_color);
  320. private dev_proc_map_rgb_color(amiga_color_map_rgb_color);
  321. private dev_proc_map_rgb_color(amiga_color_map_rgb_color_pen);
  322. private dev_proc_map_color_rgb(amiga_map_color_rgb);
  323. private dev_proc_map_color_rgb(amiga_color_map_color_rgb);
  324. private dev_proc_map_color_rgb(amiga_color_map_color_rgb_pen);
  325. private dev_proc_fill_rectangle(amiga_fill_rectangle);
  326. private dev_proc_fill_rectangle(amiga_fill_rectangle_raw);
  327. private dev_proc_fill_rectangle(amiga_fill_rectangle_raw_color);
  328. private dev_proc_copy_mono(amiga_copy_mono);
  329. private dev_proc_copy_mono(amiga_copy_mono_raw);
  330. private dev_proc_copy_mono(amiga_copy_mono_raw_color);
  331. private dev_proc_copy_color(amiga_copy_color);
  332. private dev_proc_copy_color(amiga_copy_color_raw);
  333. private dev_proc_copy_color(amiga_copy_color8);
  334. private dev_proc_copy_color(amiga_copy_color_raw_color16);
  335. private dev_proc_draw_line(amiga_draw_line);
  336. private dev_proc_draw_line(amiga_draw_line_raw);
  337. private dev_proc_draw_line(amiga_draw_line_raw_color);
  338. private dev_proc_get_bits(amiga_get_bits);
  339. private dev_proc_get_params(amiga_get_params);
  340. private dev_proc_put_params(amiga_put_params);
  341.  
  342.     /* External reference to some libraries, required for version checking, etc. */
  343.  
  344. extern struct GfxBase *GfxBase;
  345. extern struct Library *AslBase;
  346.  
  347.     /* Detect wether user has set -g and/or -r at the command line */
  348.  
  349. private BOOL ResolutionSwitch = FALSE;
  350. private BOOL GeometrySwitch = FALSE;
  351.  
  352.     /* Number of packed bytes and pack buffer. */
  353.  
  354. private LONG PackedBytes;
  355. private BYTE Buffer[MAXDAT + 1];
  356.  
  357.     /* Bit masks. */
  358.  
  359. private UBYTE shift[8] = { 128, 64, 32, 16,  8,  4,  2,  1 };
  360. private UBYTE masks[8] = { 127,191,223,239,247,251,253,254 };
  361.  
  362.     /* Dark (black) and light (white) rendering colours; the default device
  363.      * determines the actual colours to be used by looking into the screen
  364.      * colour lookup table, the other device drivers leave these values
  365.      * untouched.
  366.      */
  367.  
  368. private UBYTE DarkPen = 0;
  369. private UBYTE LightPen = 1;
  370.  
  371.     /* Device routine jump tables */
  372.  
  373. private gx_device_procs amiga_default_procs =
  374. {
  375.     amiga_open_default,
  376.     NULL,            /* get_initial_matrix */
  377.     NULL,            /* sync_output */
  378.     amiga_output_page,
  379.     amiga_close,
  380.     amiga_map_rgb_color,
  381.     amiga_map_color_rgb,
  382.     amiga_fill_rectangle,
  383.     NULL,            /* tile_rectangle */
  384.     amiga_copy_mono,
  385.     amiga_copy_color,
  386.     amiga_draw_line,
  387.     NULL,            /* get_bits */
  388.     amiga_get_params,
  389.     amiga_put_params,
  390.     NULL,            /* map_cmyk_color */
  391.     NULL,            /* get_xfont_procs */
  392.     NULL,            /* get_xfont_device */
  393.     NULL,            /* map_rgb_alpha_color */
  394.     gx_page_device_get_page_device,            /* get_page_device */
  395.     NULL,            /* get_alpha_bits */
  396.     NULL,            /* copy_alpha */
  397.     NULL,            /* get_band */
  398.     NULL,            /* copy_rop */
  399.     NULL,            /* fill_path */
  400.     NULL,            /* stroke_path */
  401.     NULL,            /* fill_mask */
  402.     NULL,            /* fill_trapezoid */
  403.     NULL,            /* fill_parallelogram */
  404.     NULL,            /* fill_triangle */
  405.     NULL,            /* draw_thin_line */
  406.     NULL,            /* begin_image */
  407.     NULL,            /* image_data */
  408.     NULL,            /* end_image */
  409.     NULL,            /* strip_tile_rectangle */
  410.     NULL,            /* strip_copy_rop */
  411. };
  412.  
  413. private gx_device_procs amiga_custom_procs =
  414. {
  415.     amiga_open_custom,
  416.     NULL,            /* get_initial_matrix */
  417.     NULL,            /* sync_output */
  418.     amiga_output_page,
  419.     amiga_close,
  420.     amiga_map_rgb_color,
  421.     amiga_map_color_rgb,
  422.     amiga_fill_rectangle,
  423.     NULL,            /* tile_rectangle */
  424.     amiga_copy_mono,
  425.     amiga_copy_color,
  426.     amiga_draw_line,
  427.     NULL,            /* get_bits */
  428.     amiga_get_params,
  429.     amiga_put_params,
  430.     NULL,            /* map_cmyk_color */
  431.     NULL,            /* get_xfont_procs */
  432.     NULL,            /* get_xfont_device */
  433.     NULL,            /* map_rgb_alpha_color */
  434.     gx_page_device_get_page_device,            /* get_page_device */
  435.     NULL,            /* get_alpha_bits */
  436.     NULL,            /* copy_alpha */
  437.     NULL,            /* get_band */
  438.     NULL,            /* copy_rop */
  439.     NULL,            /* fill_path */
  440.     NULL,            /* stroke_path */
  441.     NULL,            /* fill_mask */
  442.     NULL,            /* fill_trapezoid */
  443.     NULL,            /* fill_parallelogram */
  444.     NULL,            /* fill_triangle */
  445.     NULL,            /* draw_thin_line */
  446.     NULL,            /* begin_image */
  447.     NULL,            /* image_data */
  448.     NULL,            /* end_image */
  449.     NULL,            /* strip_tile_rectangle */
  450.     NULL,            /* strip_copy_rop */
  451. };
  452.  
  453. private gx_device_procs amiga_printer_procs =
  454. {
  455.     amiga_open_printer,
  456.     NULL,            /* get_initial_matrix */
  457.     NULL,            /* sync_output */
  458.     amiga_output_page_printer,
  459.     amiga_close_printer,
  460.     amiga_map_rgb_color,
  461.     amiga_map_color_rgb,
  462.     amiga_fill_rectangle_raw,
  463.     NULL,            /* tile_rectangle */
  464.     amiga_copy_mono_raw,
  465.     amiga_copy_color_raw,
  466.     amiga_draw_line_raw,
  467.     amiga_get_bits,
  468.     amiga_get_params,
  469.     amiga_put_params,
  470.     NULL,            /* map_cmyk_color */
  471.     NULL,            /* get_xfont_procs */
  472.     NULL,            /* get_xfont_device */
  473.     NULL,            /* map_rgb_alpha_color */
  474.     gx_page_device_get_page_device,            /* get_page_device */
  475.     NULL,            /* get_alpha_bits */
  476.     NULL,            /* copy_alpha */
  477.     NULL,            /* get_band */
  478.     NULL,            /* copy_rop */
  479.     NULL,            /* fill_path */
  480.     NULL,            /* stroke_path */
  481.     NULL,            /* fill_mask */
  482.     NULL,            /* fill_trapezoid */
  483.     NULL,            /* fill_parallelogram */
  484.     NULL,            /* fill_triangle */
  485.     NULL,            /* draw_thin_line */
  486.     NULL,            /* begin_image */
  487.     NULL,            /* image_data */
  488.     NULL,            /* end_image */
  489.     NULL,            /* strip_tile_rectangle */
  490.     NULL,            /* strip_copy_rop */
  491. };
  492.  
  493. private gx_device_procs amiga_ilbm_procs =
  494. {
  495.     amiga_open_ilbm,
  496.     NULL,            /* get_initial_matrix */
  497.     NULL,            /* sync_output */
  498.     amiga_output_page_ilbm,
  499.     amiga_close_ilbm,
  500.     amiga_map_rgb_color,
  501.     amiga_map_color_rgb,
  502.     amiga_fill_rectangle_raw,
  503.     NULL,            /* tile_rectangle */
  504.     amiga_copy_mono_raw,
  505.     amiga_copy_color_raw,
  506.     amiga_draw_line_raw,
  507.     amiga_get_bits,
  508.     amiga_get_params,
  509.     amiga_put_params,
  510.     NULL,            /* map_cmyk_color */
  511.     NULL,            /* get_xfont_procs */
  512.     NULL,            /* get_xfont_device */
  513.     NULL,            /* map_rgb_alpha_color */
  514.     gx_page_device_get_page_device,            /* get_page_device */
  515.     NULL,            /* get_alpha_bits */
  516.     NULL,            /* copy_alpha */
  517.     NULL,            /* get_band */
  518.     NULL,            /* copy_rop */
  519.     NULL,            /* fill_path */
  520.     NULL,            /* stroke_path */
  521.     NULL,            /* fill_mask */
  522.     NULL,            /* fill_trapezoid */
  523.     NULL,            /* fill_parallelogram */
  524.     NULL,            /* fill_triangle */
  525.     NULL,            /* draw_thin_line */
  526.     NULL,            /* begin_image */
  527.     NULL,            /* image_data */
  528.     NULL,            /* end_image */
  529.     NULL,            /* strip_tile_rectangle */
  530.     NULL,            /* strip_copy_rop */
  531. };
  532.  
  533.     /* Default device: opens a window on the Workbench screen and renders into it */
  534.  
  535. gx_device_amiga gs_amiga_device =
  536. {
  537.     std_device_std_body(gx_device_amiga, &amiga_default_procs, "amiga", 
  538.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  539.     { 0 },            /* std_procs */
  540.  
  541.     NULL,                /* screen */
  542.     NULL,                /* window */
  543.  
  544.     NULL,                /* super_bitmap */
  545.     NULL,                /* gadget */
  546.     NULL,                /* image */
  547.  
  548.     NULL,                /* dispatcher */
  549.     NULL,                /* main */
  550.  
  551.     NULL,                /* rport */
  552.  
  553.     NULL,                /* printer */
  554.     NULL,                /* port */
  555.     NULL,                /* colormap */
  556.     NULL,                /* bitmap */
  557.     NULL,                /* bitplane */
  558.  
  559.     1,                /* last_pen */
  560.  
  561.     DEFAULT_DISPLAYMODE,    /* display_mode */
  562.     DEFAULT_FILENAME,        /* output file */
  563.     1,                /* page counter */
  564.  
  565.     0,                /* cube_size */
  566.     NULL,                /* temp_rport */
  567.     NULL,                /* temp_array */
  568.     NULL                /* pens */
  569. };
  570.  
  571.     /* Custom device: opens a custom screen, will ask for screen mode or check env variable. */
  572.  
  573. gx_device_amiga gs_amiga_custom_device =
  574. {
  575.     std_device_std_body(gx_device_amiga, &amiga_custom_procs, "amiga_custom", 
  576.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  577.     { 0 },            /* std_procs */
  578.  
  579.     NULL,                /* screen */
  580.     NULL,                /* window */
  581.  
  582.     NULL,                /* super_bitmap */
  583.     NULL,                /* gadget */
  584.     NULL,                /* image */
  585.  
  586.     NULL,                /* dispatcher */
  587.     NULL,                /* main */
  588.  
  589.     NULL,                /* rport */
  590.  
  591.     NULL,                /* printer */
  592.     NULL,                /* port */
  593.     NULL,                /* colormap */
  594.     NULL,                /* bitmap */
  595.     NULL,                /* bitplane */
  596.  
  597.     1,                /* last_pen */
  598.  
  599.     DEFAULT_DISPLAYMODE,    /* display_mode */
  600.     DEFAULT_FILENAME,        /* output file */
  601.     1,                /* page counter */
  602.  
  603.     0,                /* cube_size */
  604.     NULL,                /* temp_rport */
  605.     NULL,                /* temp_array */
  606.     NULL                /* pens */
  607. };
  608.  
  609.     /* Printer device: renders the imagery and sends it to the printer */
  610.  
  611. gx_device_amiga gs_amiga_printer_device =
  612. {
  613.     std_device_std_body(gx_device_amiga, &amiga_printer_procs, "amiga_printer", 
  614.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  615.     { 0 },            /* std_procs */
  616.  
  617.     NULL,                /* screen */
  618.     NULL,                /* window */
  619.  
  620.     NULL,                /* super_bitmap */
  621.     NULL,                /* gadget */
  622.     NULL,                /* image */
  623.  
  624.     NULL,                /* dispatcher */
  625.     NULL,                /* main */
  626.  
  627.     NULL,                /* rport */
  628.  
  629.     NULL,                /* printer */
  630.     NULL,                /* port */
  631.     NULL,                /* colormap */
  632.     NULL,                /* bitmap */
  633.     NULL,                /* bitplane */
  634.  
  635.     1,                /* last_pen */
  636.  
  637.     DEFAULT_DISPLAYMODE,    /* display_mode */
  638.     DEFAULT_FILENAME,        /* output file */
  639.     1,                /* page counter */
  640.  
  641.     0,                /* cube_size */
  642.     NULL,                /* temp_rport */
  643.     NULL,                /* temp_array */
  644.     NULL                /* pens */
  645. };
  646.  
  647.     /* ILBM device: renders the imagery and saves it to an IFF-ILBM file. */
  648.  
  649. gx_device_amiga gs_amiga_ilbm_device =
  650. {
  651.     std_device_std_body(gx_device_amiga, &amiga_ilbm_procs, "amiga_ilbm", 
  652.         INITIAL_WIDTH, INITIAL_HEIGHT, INITIAL_X_DPI, INITIAL_Y_DPI),
  653.     { 0 },            /* std_procs */
  654.  
  655.     NULL,                /* screen */
  656.     NULL,                /* window */
  657.  
  658.     NULL,                /* super_bitmap */
  659.     NULL,                /* gadget */
  660.     NULL,                /* image */
  661.  
  662.     NULL,                /* dispatcher */
  663.     NULL,                /* main */
  664.  
  665.     NULL,                /* rport */
  666.  
  667.     NULL,                /* printer */
  668.     NULL,                /* port */
  669.     NULL,                /* colormap */
  670.     NULL,                /* bitmap */
  671.     NULL,                /* bitplane */
  672.  
  673.     1,                /* last_pen */
  674.  
  675.     DEFAULT_DISPLAYMODE,    /* display_mode */
  676.     DEFAULT_FILENAME,        /* output file */
  677.     1,                /* page counter */
  678.  
  679.     0,                /* cube_size */
  680.     NULL,                /* temp_rport */
  681.     NULL,                /* temp_array */
  682.     NULL                /* pens */
  683. };
  684.  
  685.     /* set_mono_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  686.      *
  687.      *    Reconfigure a device for monochrome output.
  688.      */
  689.  
  690. private VOID
  691. set_mono_device(gx_device_amiga *dev)
  692. {
  693.     xdev -> color_info . num_components    = 1;
  694.     xdev -> color_info . depth            = 1;
  695.     xdev -> color_info . max_gray        = 1;
  696.     xdev -> color_info . max_color        = 0;
  697.     xdev -> color_info . dither_grays    = 2;
  698.     xdev -> color_info . dither_colors    = 0;
  699.  
  700.     set_dev_proc( xdev, copy_color,    amiga_copy_color );
  701.     set_dev_proc( xdev, map_rgb_color, amiga_map_rgb_color );
  702.     set_dev_proc( xdev, map_color_rgb, amiga_map_color_rgb );
  703.  
  704. /*      xdev -> std_procs . copy_color          = amiga_copy_color;
  705.     xdev -> std_procs . map_rgb_color    = amiga_map_rgb_color;
  706.     xdev -> std_procs . map_color_rgb    = amiga_map_color_rgb;*/
  707.  
  708.     xdev -> cube_size                    = 0;
  709. }
  710.  
  711.     /* set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  712.      *
  713.      *    Reconfigure a device for colour output.
  714.      */
  715.  
  716. private VOID
  717. set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens)
  718. {
  719.     xdev -> color_info . num_components    = 3;
  720.     xdev -> color_info . depth            = 8;
  721.     xdev -> color_info . max_gray        = cube_size - 1;
  722.     xdev -> color_info . max_color        = cube_size - 1;
  723.     xdev -> color_info . dither_grays    = cube_size;
  724.     xdev -> color_info . dither_colors    = cube_size;
  725.  
  726.     set_dev_proc( xdev, copy_color,    amiga_copy_color8 );
  727. //      xdev -> std_procs . copy_color          = amiga_copy_color8;
  728.  
  729.         /* Any colours to be remapped? */
  730.  
  731.     if(pens)
  732.     {
  733.         set_dev_proc( xdev, map_rgb_color, amiga_color_map_rgb_color_pen );
  734.         set_dev_proc( xdev, map_color_rgb, amiga_color_map_color_rgb_pen );
  735.  
  736. //          xdev -> std_procs . map_rgb_color      = amiga_color_map_rgb_color_pen;
  737. //          xdev -> std_procs . map_color_rgb      = amiga_color_map_color_rgb_pen;
  738.         xdev -> pens                        = pens;
  739.     }
  740.     else
  741.     {
  742.         set_dev_proc( xdev, map_rgb_color, amiga_color_map_rgb_color );
  743.         set_dev_proc( xdev, map_color_rgb, amiga_color_map_color_rgb );
  744.  
  745. //          xdev -> std_procs . map_rgb_color      = amiga_color_map_rgb_color;
  746. //          xdev -> std_procs . map_color_rgb      = amiga_color_map_color_rgb;
  747.     }
  748.  
  749.         /* Remember the size of the RGB cube. */
  750.  
  751.     xdev -> cube_size                    = cube_size;
  752. }
  753.  
  754.     /* set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize):
  755.      *
  756.      *    Configure the printer device for colour output.
  757.      */
  758.  
  759. private VOID
  760. set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize)
  761. {
  762.     xdev -> color_info . num_components    = 3;
  763.     xdev -> color_info . depth            = 16;
  764.     xdev -> color_info . max_gray        = CubeSize - 1;
  765.     xdev -> color_info . max_color        = CubeSize - 1;
  766.     xdev -> color_info . dither_grays    = CubeSize;
  767.     xdev -> color_info . dither_colors    = CubeSize;
  768.  
  769.     set_dev_proc( xdev, fill_rectangle,    amiga_fill_rectangle_raw_color );
  770.     set_dev_proc( xdev, copy_mono, amiga_copy_mono_raw_color );
  771.     set_dev_proc( xdev, copy_color, amiga_copy_color_raw_color16 );
  772.     set_dev_proc( xdev, map_rgb_color, amiga_color_map_rgb_color );
  773.     set_dev_proc( xdev, map_color_rgb, amiga_color_map_color_rgb );
  774. /*      xdev -> std_procs . fill_rectangle  = amiga_fill_rectangle_raw_color;
  775.     xdev -> std_procs . copy_mono        = amiga_copy_mono_raw_color;
  776.     xdev -> std_procs . copy_color        = amiga_copy_color_raw_color16;
  777.     xdev -> std_procs . draw_line        = amiga_draw_line_raw_color;
  778.     xdev -> std_procs . map_rgb_color    = amiga_color_map_rgb_color;
  779.     xdev -> std_procs . map_color_rgb    = amiga_color_map_color_rgb;*/
  780.     xdev -> cube_size                    = CubeSize;
  781. }
  782.  
  783.     /* DeleteBitMap(struct BitMap *BitMap,BOOL Private):
  784.      *
  785.      *    Free memory associated with a custom rendering bitmap.
  786.      */
  787.  
  788. private VOID
  789. DeleteBitMap(struct BitMap *BitMap,BOOL Private)
  790. {
  791.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  792.         FreeBitMap(BitMap);
  793.     else
  794.     {
  795.         LONG i;
  796.  
  797.         for(i = 0 ; i < BitMap -> Depth ; i++)
  798.         {
  799.             if(BitMap -> Planes[i])
  800.                 FreeVec(BitMap -> Planes[i]);
  801.         }
  802.  
  803.         FreeVec(BitMap);
  804.     }
  805. }
  806.  
  807.     /* CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private):
  808.      *
  809.      *    Create a custom rendering bitmap.
  810.      */
  811.  
  812. private struct BitMap *
  813. CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private)
  814. {
  815.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  816.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  817.     else
  818.     {
  819.         struct BitMap    *BitMap;
  820.         LONG         Plus;
  821.         ULONG         MemType;
  822.  
  823.             /* Bitmap structure needs to be padded if more
  824.              * than the standard eight bitplanes are to be
  825.              * allocated.
  826.              */
  827.  
  828.         if(Depth > 8)
  829.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  830.         else
  831.             Plus = 0;
  832.  
  833.         if(Private)
  834.             MemType = MEMF_ANY;
  835.         else
  836.             MemType = MEMF_CHIP;
  837.  
  838.         BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap) + Plus, 
  839.             MEMF_ANY | MEMF_CLEAR);
  840.         if(BitMap)
  841.         {
  842.             LONG i,PageSize;
  843.  
  844.             InitBitMap(BitMap,Depth,Width,Height);
  845.  
  846.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  847.  
  848.             for(i = 0 ; i < BitMap -> Depth ; i++)
  849.             {
  850.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MemType)))
  851.                 {
  852.                     LONG j;
  853.  
  854.                     for(j = 0 ; j < i ; j++)
  855.                         FreeVec(BitMap -> Planes[j]);
  856.  
  857.                     FreeVec(BitMap);
  858.  
  859.                     return(NULL);
  860.                 }
  861.             }
  862.  
  863.             return(BitMap);
  864.         }
  865.         else
  866.         {
  867.             return(NULL);
  868.         }
  869.     }
  870. }
  871.  
  872.     /* DeleteTempRPort(struct RastPort *Temp):
  873.      *
  874.      *    Free memory associated with a temporary raster port.
  875.      */
  876.  
  877. private VOID
  878. DeleteTempRPort(struct RastPort *Temp)
  879. {
  880.     DeleteBitMap(Temp -> BitMap,FALSE);
  881.  
  882.     FreeVec(Temp);
  883. }
  884.  
  885.     /* CreateTempRPort(struct RastPort *Source):
  886.      *
  887.      *    Allocate memory for temporary raster port (one line high).
  888.      */
  889.  
  890. private struct RastPort *
  891. CreateTempRPort(struct RastPort *Source)
  892. {
  893.     struct RastPort *Temp;
  894.  
  895.     Temp = (struct RastPort *)AllocVec(sizeof(struct RastPort), MEMF_ANY);
  896.     if(Temp)
  897.     {
  898.         LONG Width,Depth;
  899.  
  900.         CopyMem(Source,Temp,sizeof(struct RastPort));
  901.  
  902.         Temp -> Layer = NULL;
  903.  
  904.         if(GfxBase -> LibNode . lib_Version >= 39)
  905.         {
  906.             Width    = GetBitMapAttr(Source -> BitMap,BMA_WIDTH);
  907.             Depth    = GetBitMapAttr(Source -> BitMap,BMA_DEPTH);
  908.         }
  909.         else
  910.         {
  911.             Width    = Source -> BitMap -> BytesPerRow * 8;
  912.             Depth    = Source -> BitMap -> Depth;
  913.         }
  914.  
  915.         Temp->BitMap = CreateBitMap(Width, 1, Depth, NULL, Source->BitMap, 
  916.             FALSE);
  917.         if(Temp -> BitMap)
  918.             return(Temp);
  919.         else
  920.             FreeVec(Temp);
  921.     }
  922.  
  923.     return(NULL);
  924. }
  925.  
  926.     /* Euclid(LONG a,LONG b):
  927.      *
  928.      *    Compute the greatest common divisor of two integers.
  929.      */
  930.  
  931. private LONG
  932. Euclid(LONG a,LONG b)
  933. {
  934.     do
  935.     {
  936.         if(a < b)
  937.         {
  938.             LONG t;
  939.  
  940.             t = a;
  941.             a = b;
  942.             b = t;
  943.         }
  944.  
  945.         a = a % b;
  946.     }
  947.     while(a);
  948.  
  949.     return(b);
  950. }
  951.  
  952.     /* PutDump(register BYTE *Destination,register LONG Count):
  953.      *
  954.      *    Store a byte dump.
  955.      */
  956.  
  957. private BYTE *
  958. PutDump(register BYTE *Destination,register LONG Count)
  959. {
  960.     register BYTE *Source = Buffer;
  961.  
  962.     *Destination++     = Count - 1;
  963.      PackedBytes    += Count + 1;
  964.  
  965.     while(Count--)
  966.         *Destination++ = *Source++;
  967.  
  968.     return(Destination);
  969. }
  970.  
  971.     /* PutRun(register BYTE *Destination,LONG Count,WORD Char):
  972.      *
  973.      *    Store a byte run.
  974.      */
  975.  
  976. private BYTE *
  977. PutRun(register BYTE *Destination,LONG Count,WORD Char)
  978. {
  979.     *Destination++     = -(Count - 1);
  980.     *Destination++     = Char;
  981.      PackedBytes    += 2;
  982.  
  983.     return(Destination);
  984. }
  985.  
  986.     /* PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize):
  987.      *
  988.      *    Pack a raster line using the CmpByteRun1 algorithm.
  989.      */
  990.  
  991. private LONG
  992. PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize)
  993. {
  994.     register BYTE *Source = *SourcePtr;
  995.  
  996.     WORD    Buffered    = 1,
  997.         RunStart    = 0;
  998.     BYTE    Mode        = DUMP,
  999.         LastChar,
  1000.         Char;
  1001.  
  1002.     PackedBytes = 0;
  1003.  
  1004.     Buffer[0] = LastChar = Char = *Source++;
  1005.  
  1006.     RowSize--;
  1007.  
  1008.     while(RowSize--)
  1009.     {
  1010.         Buffer[Buffered++] = Char = *Source++;
  1011.  
  1012.         if(Mode)
  1013.         {
  1014.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  1015.             {
  1016.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  1017.                 Buffer[0]    = Char;
  1018.                 Buffered    = 1;
  1019.                 RunStart    = 0;
  1020.                 Mode        = DUMP;
  1021.             }
  1022.         }
  1023.         else
  1024.         {
  1025.             if(Buffered > MAXDAT)
  1026.             {
  1027.                 Destination    = PutDump(Destination,Buffered - 1);
  1028.                 Buffer[0]    = Char;
  1029.                 Buffered    = 1;
  1030.                 RunStart    = 0;
  1031.             }
  1032.             else
  1033.             {
  1034.                 if(Char == LastChar)
  1035.                 {
  1036.                     if(Buffered - RunStart >= MINRUN)
  1037.                     {
  1038.                         if(RunStart)
  1039.                             Destination = PutDump(Destination,RunStart);
  1040.  
  1041.                         Mode = RUN;
  1042.                     }
  1043.                     else
  1044.                     {
  1045.                         if(!RunStart)
  1046.                             Mode = RUN;
  1047.                     }
  1048.                 }
  1049.                 else
  1050.                     RunStart = Buffered - 1;
  1051.             }
  1052.         }
  1053.  
  1054.         LastChar = Char;
  1055.     }
  1056.  
  1057.     if(Mode)
  1058.         PutRun(Destination,Buffered - RunStart,LastChar);
  1059.     else
  1060.         PutDump(Destination,Buffered);
  1061.  
  1062.     *SourcePtr = Source;
  1063.  
  1064.     return(PackedBytes);
  1065. }
  1066.  
  1067.     /* PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap):
  1068.      *
  1069.      *    Store a bitmap in a BODY chunk.
  1070.      */
  1071.  
  1072. private BOOL
  1073. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap)
  1074. {
  1075.     PLANEPTR    *Planes;
  1076.     BYTE        *PackBuffer;
  1077.     BOOL         Success = FALSE;
  1078.     LONG         PackedBytes,
  1079.              i,j;
  1080.  
  1081.         /* Allocate the bitplane information. */
  1082.  
  1083.     Planes = (PLANEPTR *)AllocVec(BitMap->Depth * sizeof(PLANEPTR *), 
  1084.         MEMF_ANY | MEMF_CLEAR);
  1085.     if(Planes)
  1086.     {
  1087.             /* Allocate the compression buffer. */
  1088.  
  1089.         PackBuffer = (BYTE *)AllocVec(BitMap->BytesPerRow * 2, MEMF_ANY);
  1090.         if(PackBuffer)
  1091.         {
  1092.                 /* Copy the planes over. */
  1093.  
  1094.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1095.                 Planes[i] = BitMap -> Planes[i];
  1096.  
  1097.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  1098.             {
  1099.                 Success = TRUE;
  1100.  
  1101.                     /* Run down the rows. */
  1102.  
  1103.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  1104.                 {
  1105.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  1106.                     {
  1107.                             /* Pack the data. */
  1108.  
  1109.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  1110.  
  1111.                             /* Write it to disk. */
  1112.  
  1113.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  1114.                             Success = FALSE;
  1115.                     }
  1116.                 }
  1117.  
  1118.                 if(PopChunk(Handle))
  1119.                     Success = FALSE;
  1120.             }
  1121.  
  1122.             FreeVec(PackBuffer);
  1123.         }
  1124.  
  1125.         FreeVec(Planes);
  1126.     }
  1127.  
  1128.     return(Success);
  1129. }
  1130.  
  1131.     /* PutANNO(struct IFFHandle *Handle):
  1132.      *
  1133.      *    Store annotation chunk.
  1134.      */
  1135.  
  1136. private BOOL
  1137. PutANNO(struct IFFHandle *Handle)
  1138. {
  1139.     STATIC unsigned char Note[256];
  1140.  
  1141.     sprintf(Note, "Image generated by %s %d.%02d (device=amiga_ilbm)", 
  1142.         gs_product, (int)(gs_revision / 100), (int)(gs_revision % 100));
  1143.  
  1144.     if(!PushChunk(Handle,0,ID_ANNO,strlen(Note)))
  1145.     {
  1146.         if(WriteChunkRecords(Handle,Note,strlen(Note),1) == 1)
  1147.         {
  1148.             if(!PopChunk(Handle))
  1149.                 return(TRUE);
  1150.         }
  1151.     }
  1152.  
  1153.     return(FALSE);
  1154. }
  1155.  
  1156.     /* PutCAMG(struct IFFHandle *Handle):
  1157.      *
  1158.      *    Store display mode chunk.
  1159.      */
  1160.  
  1161. private BOOL
  1162. PutCAMG(struct IFFHandle *Handle)
  1163. {
  1164.     ULONG ViewModes = HIRESLACE_KEY;
  1165.  
  1166.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  1167.     {
  1168.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  1169.         {
  1170.             if(!PopChunk(Handle))
  1171.                 return(TRUE);
  1172.         }
  1173.     }
  1174.  
  1175.     return(FALSE);
  1176. }
  1177.  
  1178.     /* PutCMAP(struct IFFHandle *Handle):
  1179.      *
  1180.      *    Store colour map chunk.
  1181.      */
  1182.  
  1183. private BOOL
  1184. PutCMAP(struct IFFHandle *Handle)
  1185. {
  1186.     STATIC UBYTE Colours[2][3] =
  1187.     {
  1188.         { 0x00,0x00,0x00, },
  1189.         { 0xFF,0xFF,0xFF, },
  1190.     };
  1191.  
  1192.     if(!PushChunk(Handle,0,ID_CMAP,sizeof(Colours)))
  1193.     {
  1194.         if(WriteChunkRecords(Handle,Colours,2,3) == 3)
  1195.         {
  1196.             if(!PopChunk(Handle))
  1197.                 return(TRUE);
  1198.         }
  1199.     }
  1200.  
  1201.     return(FALSE);
  1202. }
  1203.  
  1204.     /* PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI):
  1205.      *
  1206.      *    Store DPI chunk.
  1207.      */
  1208.  
  1209. private BOOL
  1210. PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI)
  1211. {
  1212.     DPIHeader Header;
  1213.  
  1214.     Header . dpi_x = X_DPI;
  1215.     Header . dpi_y = Y_DPI;
  1216.  
  1217.     if(!PushChunk(Handle,0,ID_DPI,sizeof(Header)))
  1218.     {
  1219.         if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1220.         {
  1221.             if(!PopChunk(Handle))
  1222.                 return(TRUE);
  1223.         }
  1224.     }
  1225.  
  1226.     return(FALSE);
  1227. }
  1228.  
  1229.     /* PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1230.      *
  1231.      *    Store BMHD chunk.
  1232.      */
  1233.  
  1234. private BOOL
  1235. PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1236. {
  1237.         /* Valid parameters? */
  1238.  
  1239.     if(X_DPI > 0 && Y_DPI > 0 && Width > 0 && Height > 0)
  1240.     {
  1241.         struct BitMapHeader    Header;
  1242.         UWORD        gcd;
  1243.  
  1244.             /* So we can store neat & small
  1245.              * aspect ration values.
  1246.              */
  1247.  
  1248.         gcd = Euclid(X_DPI,Y_DPI);
  1249.  
  1250.         Header . bmh_Width            = Width;
  1251.         Header . bmh_Height            = Height;
  1252.         Header . bmh_Left            = 0;
  1253.         Header . bmh_Top            = 0;
  1254.         Header . bmh_Depth            = 1;
  1255.         Header . bmh_Masking        = 0;
  1256.         Header . bmh_Compression    = 1;
  1257.         Header . bmh_Pad            = 0;
  1258.         Header . bmh_Transparent    = 0;
  1259.         Header . bmh_XAspect        = X_DPI / gcd;
  1260.         Header . bmh_YAspect        = Y_DPI / gcd;
  1261.         Header . bmh_PageWidth        = Width;
  1262.         Header . bmh_PageHeight        = Height;
  1263.  
  1264.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(Header)))
  1265.         {
  1266.             if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1267.             {
  1268.                 if(!PopChunk(Handle))
  1269.                     return(TRUE);
  1270.             }
  1271.         }
  1272.     }
  1273.  
  1274.     return(FALSE);
  1275. }
  1276.  
  1277.     /* SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1278.      *
  1279.      *    Store a bitmap in an IFF-ILBM file.
  1280.      */
  1281.  
  1282. private BOOL
  1283. SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1284. {
  1285.     struct IFFHandle    *Handle;
  1286.     BOOL             Success = FALSE;
  1287.  
  1288.     Handle = AllocIFF();
  1289.     if(Handle)
  1290.     {
  1291.         Handle -> iff_Stream = Open(Name, MODE_NEWFILE);
  1292.         if(Handle)
  1293.         {
  1294.             InitIFFasDOS(Handle);
  1295.  
  1296.             if(!OpenIFF(Handle,IFFF_WRITE))
  1297.             {
  1298.                 if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  1299.                 {
  1300.                     if(PutBMHD(Handle,Width,Height,X_DPI,Y_DPI))
  1301.                     {
  1302.                         if(PutANNO(Handle))
  1303.                         {
  1304.                             if(PutCMAP(Handle))
  1305.                             {
  1306.                                 if(PutCAMG(Handle))
  1307.                                 {
  1308.                                     if(PutDPI(Handle,X_DPI,Y_DPI))
  1309.                                     {
  1310.                                         if(PutBODY(Handle,BitMap))
  1311.                                             Success = TRUE;
  1312.                                     }
  1313.                                 }
  1314.                             }
  1315.                         }
  1316.                     }
  1317.  
  1318.                     if(PopChunk(Handle))
  1319.                         Success = FALSE;
  1320.                 }
  1321.  
  1322.                 CloseIFF(Handle);
  1323.             }
  1324.  
  1325.             Close(Handle -> iff_Stream);
  1326.  
  1327.             if(!Success)
  1328.                 DeleteFile(Name);
  1329.         }
  1330.  
  1331.         FreeIFF(Handle);
  1332.     }
  1333.  
  1334.     return(Success);
  1335. }
  1336.  
  1337.     /* DispatchTask():
  1338.      *
  1339.      *    Asynchronous window message dispatcher.
  1340.      */
  1341.  
  1342. private VOID
  1343. DispatchTask()
  1344. {
  1345.     struct Task    *me;
  1346.     gx_device    *dev;
  1347.  
  1348.         /* Set up global data area base register. */
  1349. #ifdef IXEMUL
  1350.     ix_geta4();
  1351. #endif
  1352.         /* Who am I? */
  1353.     me = FindTask(NULL);
  1354.  
  1355. #ifdef __PPC__
  1356.     dev = DispatchTaskDevice;
  1357. #else
  1358.         /* Wait for wakeup call. */
  1359.  
  1360.     Wait(SIG_WAKEUP);
  1361.  
  1362.         /* Obtain device pointer. */
  1363.  
  1364.     dev = me -> tc_UserData;
  1365. #endif
  1366.  
  1367.         /* Enable user input. */
  1368.  
  1369.     if(ModifyIDCMP(xdev -> window,IDCMP_FLAGS))
  1370.     {
  1371.         ULONG    Mask = 1 << xdev -> window -> UserPort -> mp_SigBit,
  1372.             Set;
  1373.         BOOL    Done = FALSE;
  1374.  
  1375.             /* Fill in the dispatcher entry. */
  1376.  
  1377.         xdev -> dispatcher = me;
  1378.  
  1379.             /* Ring back. */
  1380.  
  1381.         Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1382.  
  1383.             /* Wait for input... */
  1384.  
  1385.         do
  1386.         {
  1387.             Set = Wait(Mask | SIG_KILL);
  1388.  
  1389.             if(Set & Mask)
  1390.                 DispatchSuperWindow(dev);
  1391.  
  1392.             if(Set & SIG_KILL)
  1393.                 Done = TRUE;
  1394.         }
  1395.         while(!Done);
  1396.  
  1397.             /* Disable user input. */
  1398.  
  1399.         ModifyIDCMP(xdev -> window,NULL);
  1400.     }
  1401.  
  1402. #ifndef __PPC__
  1403.         /* Disable task switching. */
  1404.  
  1405.     Forbid();
  1406.  
  1407.         /* Clear the dispatcher entry. */
  1408.  
  1409.     xdev -> dispatcher = NULL;
  1410.  
  1411.         /* Signal the main process that we are done. */
  1412.  
  1413.     Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1414.  
  1415.         /* Enable task switching. */
  1416.  
  1417.     Permit();
  1418. #endif
  1419.  
  1420.         /* Remove ourselves. */
  1421.  
  1422.     RemTask(NULL);
  1423. }
  1424.  
  1425.     /* DeleteScrollers(gx_device *dev):
  1426.      *
  1427.      *    Delete the window border scrollers.
  1428.      */
  1429.  
  1430. private VOID
  1431. DeleteScrollers(gx_device *dev)
  1432. {
  1433.     if(xdev -> gadget)
  1434.     {
  1435.         if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1436.             DisposeObject(xdev -> gadget[HORIZONTAL_SCROLLER]);
  1437.  
  1438.         if(xdev -> gadget[VERTICAL_SCROLLER])
  1439.             DisposeObject(xdev -> gadget[VERTICAL_SCROLLER]);
  1440.  
  1441.         if(xdev -> gadget[UP_ARROW])
  1442.             DisposeObject(xdev -> gadget[UP_ARROW]);
  1443.  
  1444.         if(xdev -> gadget[DOWN_ARROW])
  1445.             DisposeObject(xdev -> gadget[DOWN_ARROW]);
  1446.  
  1447.         if(xdev -> gadget[LEFT_ARROW])
  1448.             DisposeObject(xdev -> gadget[LEFT_ARROW]);
  1449.  
  1450.         if(xdev -> gadget[RIGHT_ARROW])
  1451.             DisposeObject(xdev -> gadget[RIGHT_ARROW]);
  1452.  
  1453.         FreeVec(xdev -> gadget);
  1454.  
  1455.         xdev -> gadget = NULL;
  1456.     }
  1457.  
  1458.     if(xdev -> image)
  1459.     {
  1460.         if(xdev -> image[UP_IMAGE])
  1461.             DisposeObject(xdev -> image[UP_IMAGE]);
  1462.  
  1463.         if(xdev -> image[DOWN_IMAGE])
  1464.             DisposeObject(xdev -> image[DOWN_IMAGE]);
  1465.  
  1466.         if(xdev -> image[LEFT_IMAGE])
  1467.             DisposeObject(xdev -> image[LEFT_IMAGE]);
  1468.  
  1469.         if(xdev -> image[RIGHT_IMAGE])
  1470.             DisposeObject(xdev -> image[RIGHT_IMAGE]);
  1471.  
  1472.         FreeVec(xdev -> image);
  1473.  
  1474.         xdev -> image = NULL;
  1475.     }
  1476. }
  1477.  
  1478.     /* CreateScrollers(gx_device *dev,struct Screen *Screen):
  1479.      *
  1480.      *    Create the window border scroller handles.
  1481.      */
  1482.  
  1483. private BOOL
  1484. CreateScrollers(gx_device *dev,struct Screen *Screen)
  1485. {
  1486.     BOOL Result = FALSE;
  1487.  
  1488.     xdev -> gadget = (struct Gadget **)AllocVec(sizeof(struct Gadget *) 
  1489.         * GADGET_COUNT, MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC);
  1490.     if(xdev -> gadget)
  1491.     {
  1492.         xdev -> image = (struct Image **)AllocVec(sizeof(struct Image *) 
  1493.             * IMAGE_COUNT, MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC);
  1494.         if(xdev -> image)
  1495.         {
  1496.             struct DrawInfo *DrawInfo;
  1497.  
  1498.             DrawInfo = GetScreenDrawInfo(Screen);
  1499.             if(DrawInfo)
  1500.             {
  1501.                 ULONG     SizeWidth,
  1502.                      SizeHeight;
  1503.                 ULONG     ArrowWidth,
  1504.                      ArrowHeight;
  1505.                 UWORD     SizeType;
  1506.                 Object    *SizeImage;
  1507.  
  1508.                 if(Screen -> Flags & SCREENHIRES)
  1509.                 {
  1510.                     SizeWidth    = 18;
  1511.                     SizeHeight    = 10;
  1512.  
  1513.                     SizeType    = SYSISIZE_MEDRES;
  1514.                 }
  1515.                 else
  1516.                 {
  1517.                     SizeWidth    = 13;
  1518.                     SizeHeight    = 11;
  1519.  
  1520.                     SizeType    = SYSISIZE_LOWRES;
  1521.                 }
  1522.  
  1523.                 SizeImage = NewObject(NULL, SYSICLASS, 
  1524.                     SYSIA_Size,    SizeType,
  1525.                     SYSIA_Which,    SIZEIMAGE,
  1526.                     SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1527.                     TAG_DONE);
  1528.                 if(SizeImage)
  1529.                 {
  1530.                     GetAttr(IA_Width,    SizeImage,&SizeWidth);
  1531.                     GetAttr(IA_Height,    SizeImage,&SizeHeight);
  1532.  
  1533.                     DisposeObject(SizeImage);
  1534.                 }
  1535.  
  1536.                 xdev -> image[UP_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1537.                     SYSIA_Size,    SizeType,
  1538.                     SYSIA_Which,    UPIMAGE,
  1539.                     SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1540.                     TAG_DONE);
  1541.                 if(xdev -> image[UP_IMAGE])
  1542.                 {
  1543.                     GetAttr(IA_Height,xdev -> image[UP_IMAGE],&ArrowHeight);
  1544.  
  1545.                     xdev -> image[DOWN_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1546.                         SYSIA_Size,    SizeType,
  1547.                         SYSIA_Which,    DOWNIMAGE,
  1548.                         SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1549.                         TAG_DONE);
  1550.                     if(xdev -> image[DOWN_IMAGE])
  1551.                     {
  1552.                         xdev -> image[LEFT_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1553.                             SYSIA_Size,    SizeType,
  1554.                             SYSIA_Which,    LEFTIMAGE,
  1555.                             SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1556.                             TAG_DONE);
  1557.                         if(xdev -> image[LEFT_IMAGE])
  1558.                         {
  1559.                             GetAttr(IA_Width,xdev -> image[LEFT_IMAGE],&ArrowWidth);
  1560.  
  1561.                             xdev -> image[RIGHT_IMAGE] = (struct Image *)NewObject(NULL, SYSICLASS,
  1562.                                 SYSIA_Size,    SizeType,
  1563.                                 SYSIA_Which,    RIGHTIMAGE,
  1564.                                 SYSIA_DrawInfo,    (ULONG)DrawInfo,
  1565.                                 TAG_DONE);
  1566.                             if(xdev -> image[RIGHT_IMAGE])
  1567.                             {
  1568.                                 xdev -> gadget[VERTICAL_SCROLLER] = NewObject(NULL, PROPGCLASS,
  1569.                                     GA_ID,        VERTICAL_SCROLLER,
  1570.  
  1571.                                     GA_Top,        Screen -> WBorTop + Screen -> Font -> ta_YSize + 2,
  1572.                                     GA_RelHeight,    -(Screen -> WBorTop + Screen -> Font -> ta_YSize + 2 + SizeHeight + 1 + 2 * ArrowHeight),
  1573.                                     GA_Width,    SizeWidth - 8,
  1574.                                     GA_RelRight,    -(SizeWidth - 5),
  1575.  
  1576.                                     GA_GZZGadget,    TRUE,
  1577.                                     GA_Immediate,    TRUE,
  1578.                                     GA_FollowMouse,    TRUE,
  1579.                                     GA_RelVerify,    TRUE,
  1580.                                     GA_RightBorder,    TRUE,
  1581.  
  1582.                                     PGA_Freedom,    FREEVERT,
  1583.                                     PGA_NewLook,    TRUE,
  1584.                                     PGA_Borderless,    TRUE,
  1585.  
  1586.                                     PGA_Visible,    1,
  1587.                                     PGA_Total,    1,
  1588.                                     TAG_DONE);
  1589.                                 if(xdev -> gadget[VERTICAL_SCROLLER])
  1590.                                 {
  1591.                                     xdev -> gadget[HORIZONTAL_SCROLLER] = NewObject(NULL, PROPGCLASS,
  1592.                                         GA_ID,        HORIZONTAL_SCROLLER,
  1593.                                         GA_Previous,    (ULONG)(xdev -> gadget[VERTICAL_SCROLLER]),
  1594.  
  1595.                                         GA_Height,    SizeHeight - 4,
  1596.                                         GA_RelBottom,    -(SizeHeight - 4 + 1),
  1597.                                         GA_Left,    4,
  1598.                                         GA_RelWidth,    -(2 + SizeWidth + 4 + 2 * ArrowWidth),
  1599.  
  1600.                                         GA_GZZGadget,    TRUE,
  1601.                                         GA_Immediate,    TRUE,
  1602.                                         GA_FollowMouse,    TRUE,
  1603.                                         GA_RelVerify,    TRUE,
  1604.                                         GA_BottomBorder,TRUE,
  1605.  
  1606.                                         PGA_Freedom,    FREEHORIZ,
  1607.                                         PGA_NewLook,    TRUE,
  1608.                                         PGA_Borderless,    TRUE,
  1609.  
  1610.                                         PGA_Visible,    1,
  1611.                                         PGA_Total,    1,
  1612.                                         TAG_DONE);
  1613.                                     if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1614.                                     {
  1615.                                         STATIC struct TagItem ArrowMappings[] = 
  1616.                                         { 
  1617.                                             { GA_ID, GA_ID, },
  1618.                                             { TAG_END, },
  1619.                                         };
  1620.  
  1621.                                         xdev -> gadget[UP_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1622.                                             GA_ID,        UP_ARROW,
  1623.                                             GA_Previous,    (ULONG)(xdev -> gadget[HORIZONTAL_SCROLLER]),
  1624.  
  1625.                                             GA_GZZGadget,    TRUE,
  1626.                                             GA_Image,    (ULONG)(xdev -> image[UP_IMAGE]),
  1627.                                             GA_RelRight,    -(SizeWidth - 1),
  1628.                                             GA_RelBottom,    -(SizeHeight - 1 + 2 * ArrowHeight),
  1629.                                             GA_Height,    ArrowHeight,
  1630.                                             GA_Width,    SizeWidth,
  1631.                                             GA_Immediate,    TRUE,
  1632.                                             GA_RelVerify,    TRUE,
  1633.                                             GA_RightBorder,    TRUE,
  1634.  
  1635.                                             ICA_TARGET,    ICTARGET_IDCMP,
  1636.                                             ICA_MAP,    (ULONG)ArrowMappings,
  1637.                                             TAG_DONE);
  1638.                                         if(xdev -> gadget[UP_ARROW])
  1639.                                         {
  1640.                                             xdev -> gadget[DOWN_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1641.                                                 GA_ID,        DOWN_ARROW,
  1642.                                                 GA_Previous,    (ULONG)(xdev -> gadget[UP_ARROW]),
  1643.  
  1644.                                                 GA_GZZGadget,    TRUE,
  1645.                                                 GA_Image,    (ULONG)(xdev -> image[DOWN_IMAGE]),
  1646.                                                 GA_RelRight,    -(SizeWidth - 1),
  1647.                                                 GA_RelBottom,    -(SizeHeight - 1 + ArrowHeight),
  1648.                                                 GA_Height,    ArrowHeight,
  1649.                                                 GA_Width,    SizeWidth,
  1650.                                                 GA_Immediate,    TRUE,
  1651.                                                 GA_RelVerify,    TRUE,
  1652.                                                 GA_RightBorder,    TRUE,
  1653.  
  1654.                                                 ICA_TARGET,    ICTARGET_IDCMP,
  1655.                                                 ICA_MAP,    (ULONG)ArrowMappings,
  1656.                                                 TAG_DONE);
  1657.                                             if(xdev -> gadget[DOWN_ARROW])
  1658.                                             {
  1659.                                                 xdev -> gadget[LEFT_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1660.                                                     GA_ID,        LEFT_ARROW,
  1661.                                                     GA_Previous,    (ULONG)(xdev -> gadget[DOWN_ARROW]),
  1662.  
  1663.                                                     GA_GZZGadget,    TRUE,
  1664.                                                     GA_Image,    (ULONG)(xdev -> image[LEFT_IMAGE]),
  1665.                                                     GA_RelRight,    -(SizeWidth - 1 + 2 * ArrowWidth),
  1666.                                                     GA_RelBottom,    -(SizeHeight - 1),
  1667.                                                     GA_Height,    SizeHeight,
  1668.                                                     GA_Width,    ArrowWidth,
  1669.                                                     GA_Immediate,    TRUE,
  1670.                                                     GA_RelVerify,    TRUE,
  1671.                                                     GA_BottomBorder,TRUE,
  1672.  
  1673.                                                     ICA_TARGET,    ICTARGET_IDCMP,
  1674.                                                     ICA_MAP,    (ULONG)ArrowMappings,
  1675.                                                     TAG_DONE);
  1676.                                                 if(xdev -> gadget[LEFT_ARROW])
  1677.                                                 {
  1678.                                                     xdev -> gadget[RIGHT_ARROW] = NewObject(NULL, BUTTONGCLASS,
  1679.                                                         GA_ID,        RIGHT_ARROW,
  1680.                                                         GA_Previous,    (ULONG)(xdev -> gadget[LEFT_ARROW]),
  1681.  
  1682.                                                         GA_GZZGadget,    TRUE,
  1683.                                                         GA_Image,    (ULONG)(xdev -> image[RIGHT_IMAGE]),
  1684.                                                         GA_RelRight,    -(SizeWidth - 1 + ArrowWidth),
  1685.                                                         GA_RelBottom,    -(SizeHeight - 1),
  1686.                                                         GA_Height,    SizeHeight,
  1687.                                                         GA_Width,    ArrowWidth,
  1688.                                                         GA_Immediate,    TRUE,
  1689.                                                         GA_RelVerify,    TRUE,
  1690.                                                         GA_BottomBorder,TRUE,
  1691.  
  1692.                                                         ICA_TARGET,    ICTARGET_IDCMP,
  1693.                                                         ICA_MAP,    (ULONG)ArrowMappings,
  1694.                                                         TAG_DONE);
  1695.                                                     if(xdev -> gadget[RIGHT_ARROW])
  1696.                                                         Result = TRUE;
  1697.                                                 }
  1698.                                             }
  1699.                                         }
  1700.                                     }
  1701.                                 }
  1702.                             }
  1703.                         }
  1704.                     }
  1705.                 }
  1706.  
  1707.                 FreeScreenDrawInfo(Screen,DrawInfo);
  1708.             }
  1709.         }
  1710.     }
  1711.  
  1712.     return(Result);
  1713. }
  1714.  
  1715.     /* WindowResize(gx_device *dev):
  1716.      *
  1717.      *    Update the slider sizes and positions after the window
  1718.      *    was resized.
  1719.      */
  1720.  
  1721. private VOID
  1722. WindowResize(gx_device *dev)
  1723. {
  1724.     LONG    DeltaX,
  1725.         DeltaY,
  1726.         Temp;
  1727.  
  1728.         /* Query the current horizontal slider position. */
  1729.  
  1730.     if((Temp = LAYERXOFFSET(xdev -> window) + xdev -> window -> GZZWidth) > xdev -> width)
  1731.         DeltaX = xdev -> width - Temp;
  1732.     else
  1733.         DeltaX = 0;
  1734.  
  1735.         /* Query the current vertical slider position. */
  1736.  
  1737.     if((Temp = LAYERYOFFSET(xdev -> window) + xdev -> window -> GZZHeight) > xdev -> height)
  1738.         DeltaY = xdev -> height - Temp;
  1739.     else
  1740.         DeltaY = 0;
  1741.  
  1742.         /* Move the currently displayed window area around. */
  1743.  
  1744.     if(DeltaX || DeltaY)
  1745.         ScrollLayer(NULL,xdev -> window -> RPort -> Layer,DeltaX,DeltaY);
  1746.  
  1747.         /* Update the new horizontal slider position and size. */
  1748.  
  1749.     SetGadgetAttrs(xdev -> gadget[HORIZONTAL_SCROLLER],xdev -> window,NULL,
  1750.         PGA_Top,    LAYERXOFFSET(xdev -> window),
  1751.         PGA_Visible,    xdev -> window -> GZZWidth,
  1752.         PGA_Total,    xdev -> width,
  1753.     TAG_DONE);
  1754.  
  1755.         /* Update the new vertical slider position and size. */
  1756.  
  1757.     SetGadgetAttrs(xdev -> gadget[VERTICAL_SCROLLER],xdev -> window,NULL,
  1758.         PGA_Top,    LAYERYOFFSET(xdev -> window),
  1759.         PGA_Visible,    xdev -> window -> GZZHeight,
  1760.         PGA_Total,    xdev -> height,
  1761.     TAG_DONE);
  1762. }
  1763.  
  1764.     /* WindowUpdate(struct Gadget *Gadget,gx_device *dev):
  1765.      *
  1766.      *    Move the currently visible portion of the
  1767.      *    window according to the current slider
  1768.      *    position.
  1769.      */
  1770.  
  1771. private VOID
  1772. WindowUpdate(struct Gadget *Gadget,gx_device *dev)
  1773. {
  1774.     LONG Storage;
  1775.  
  1776.     switch(Gadget -> GadgetID)
  1777.     {
  1778.         case HORIZONTAL_SCROLLER:
  1779.  
  1780.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1781.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  1782.  
  1783.             break;
  1784.  
  1785.         case VERTICAL_SCROLLER:
  1786.  
  1787.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1788.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  1789.  
  1790.             break;
  1791.     }
  1792. }
  1793.  
  1794.     /* MoveAround(struct Gadget *Gadget,int How,gx_device *dev):
  1795.      *
  1796.      *    Move the currently visible window area according to
  1797.      *    user input.
  1798.      */
  1799.  
  1800. private VOID
  1801. MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev)
  1802. {
  1803.     LONG Storage;
  1804.  
  1805.     if(GetAttr(PGA_Top,Gadget,&Storage))
  1806.     {
  1807.         LONG Max = 0;
  1808.  
  1809.         switch(Gadget -> GadgetID)
  1810.         {
  1811.             case HORIZONTAL_SCROLLER:
  1812.  
  1813.                 Max = xdev -> width - xdev -> window -> GZZWidth;
  1814.                 break;
  1815.  
  1816.             case VERTICAL_SCROLLER:
  1817.  
  1818.                 Max = xdev -> height - xdev -> window -> GZZHeight;
  1819.                 break;
  1820.         }
  1821.  
  1822.         switch(How)
  1823.         {
  1824.             case MOVE_MIN:
  1825.  
  1826.                 Storage = 0;
  1827.                 break;
  1828.  
  1829.             case MOVE_MAX:
  1830.  
  1831.                 Storage = Max;
  1832.                 break;
  1833.  
  1834.             case MOVE_DOWN:
  1835.  
  1836.                 if(Storage > xdev -> height / 100)
  1837.                     Storage -= xdev -> height / 100;
  1838.                 else
  1839.                     Storage = 0;
  1840.  
  1841.                 break;
  1842.  
  1843.             case MOVE_FAR_DOWN:
  1844.  
  1845.                 if(Storage > xdev -> height / 10)
  1846.                     Storage -= xdev -> height / 10;
  1847.                 else
  1848.                     Storage = 0;
  1849.  
  1850.                 break;
  1851.  
  1852.             case MOVE_FAR_UP:
  1853.  
  1854.                 if(Storage + xdev -> width / 10 < Max)
  1855.                     Storage += xdev -> width / 10;
  1856.                 else
  1857.                     Storage = Max;
  1858.  
  1859.                 break;
  1860.  
  1861.             case MOVE_UP:
  1862.  
  1863.                 if(Storage + xdev -> width / 100 < Max)
  1864.                     Storage += xdev -> width / 100;
  1865.                 else
  1866.                     Storage = Max;
  1867.  
  1868.                 break;
  1869.         }
  1870.  
  1871.         switch(Gadget -> GadgetID)
  1872.         {
  1873.             case HORIZONTAL_SCROLLER:
  1874.  
  1875.                 if(LAYERXOFFSET(xdev -> window) != Storage)
  1876.                 {
  1877.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  1878.  
  1879.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  1880.                         PGA_Top,Storage,
  1881.                     TAG_DONE);
  1882.                 }
  1883.  
  1884.                 break;
  1885.  
  1886.             case VERTICAL_SCROLLER:
  1887.  
  1888.                 if(LAYERYOFFSET(xdev -> window) != Storage)
  1889.                 {
  1890.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  1891.  
  1892.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  1893.                         PGA_Top,Storage,
  1894.                     TAG_DONE);
  1895.                 }
  1896.  
  1897.                 break;
  1898.         }
  1899.     }
  1900. }
  1901.  
  1902.     /* DispatchSuperWindow(gx_device *dev):
  1903.      *
  1904.      *    Dispatch user window input.
  1905.      */
  1906.  
  1907. private VOID
  1908. DispatchSuperWindow(gx_device *dev)
  1909. {
  1910.     STATIC struct Gadget    *CurrentGadget = NULL;
  1911.  
  1912.     struct IntuiMessage    *IntuiMessage;
  1913.     ULONG             MsgClass,
  1914.                  MsgCode,
  1915.                  MsgQualifier;
  1916.     struct Gadget        *MsgGadget;
  1917.  
  1918.     while(NULL != (IntuiMessage = (struct IntuiMessage *)GetMsg(
  1919.         xdev -> window -> UserPort)))
  1920.     {
  1921.         MsgClass    = IntuiMessage -> Class;
  1922.         MsgCode        = IntuiMessage -> Code;
  1923.         MsgQualifier    = IntuiMessage -> Qualifier;
  1924.         MsgGadget    = IntuiMessage -> IAddress;
  1925.  
  1926.         ReplyMsg((struct Message *)IntuiMessage);
  1927.  
  1928.         switch(MsgClass)
  1929.         {
  1930.             case IDCMP_VANILLAKEY:
  1931.  
  1932.                 if(MsgCode == '\033' || MsgCode == '\003')
  1933.                     Signal((struct Task *)xdev -> main,SIG_KILL);
  1934.  
  1935.                 break;
  1936.  
  1937.             case IDCMP_RAWKEY:
  1938.  
  1939.                 switch(MsgCode)
  1940.                 {
  1941.                     case HELP_CODE:
  1942.  
  1943.                         DisplayBeep(xdev -> window -> WScreen);
  1944.  
  1945.                         break;
  1946.  
  1947.                     case CURSORUP:
  1948.  
  1949.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1950.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MIN,dev);
  1951.                         else
  1952.                         {
  1953.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1954.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_DOWN,dev);
  1955.                             else
  1956.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  1957.                         }
  1958.  
  1959.                         break;
  1960.  
  1961.                     case CURSORLEFT:
  1962.  
  1963.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1964.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MIN,dev);
  1965.                         else
  1966.                         {
  1967.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1968.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_DOWN,dev);
  1969.                             else
  1970.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  1971.                         }
  1972.  
  1973.                         break;
  1974.  
  1975.                     case CURSORRIGHT:
  1976.  
  1977.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1978.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MAX,dev);
  1979.                         else
  1980.                         {
  1981.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1982.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_UP,dev);
  1983.                             else
  1984.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  1985.                         }
  1986.  
  1987.                         break;
  1988.  
  1989.                     case CURSORDOWN:
  1990.  
  1991.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  1992.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MAX,dev);
  1993.                         else
  1994.                         {
  1995.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1996.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_UP,dev);
  1997.                             else
  1998.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  1999.                         }
  2000.  
  2001.                         break;
  2002.  
  2003.                     default:
  2004.  
  2005.                         break;
  2006.                 }
  2007.  
  2008.                 break;
  2009.  
  2010.             case IDCMP_CLOSEWINDOW:
  2011.  
  2012.                 Signal((struct Task *)xdev -> main,SIG_KILL);
  2013.  
  2014.                 break;
  2015.  
  2016.             case IDCMP_GADGETDOWN:
  2017.  
  2018.                 CurrentGadget = MsgGadget;
  2019.  
  2020.                 WindowUpdate(MsgGadget,dev);
  2021.  
  2022.                 break;
  2023.  
  2024.             case IDCMP_GADGETUP:
  2025.  
  2026.                 CurrentGadget = NULL;
  2027.  
  2028.                 WindowUpdate(MsgGadget,dev);
  2029.  
  2030.                 break;
  2031.  
  2032.             case IDCMP_MOUSEMOVE:
  2033.  
  2034.                 if(CurrentGadget)
  2035.                     WindowUpdate(CurrentGadget,dev);
  2036.  
  2037.                 break;
  2038.  
  2039.             case IDCMP_IDCMPUPDATE:
  2040.  
  2041.                 switch(GetTagData(GA_ID,0,(struct TagItem *)MsgGadget))
  2042.                 {
  2043.                     case UP_ARROW:
  2044.  
  2045.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2046.                         break;
  2047.  
  2048.                     case DOWN_ARROW:
  2049.  
  2050.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2051.                         break;
  2052.  
  2053.                     case LEFT_ARROW:
  2054.  
  2055.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2056.                         break;
  2057.  
  2058.                     case RIGHT_ARROW:
  2059.  
  2060.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2061.                         break;
  2062.  
  2063.                     default:
  2064.  
  2065.                         break;
  2066.                 }
  2067.  
  2068.                 break;
  2069.  
  2070.             case IDCMP_NEWSIZE:
  2071.  
  2072.                 WindowResize(dev);
  2073.  
  2074.                 break;
  2075.  
  2076.             default:
  2077.  
  2078.                 break;
  2079.         }
  2080.     }
  2081. }
  2082.  
  2083.     /* PrintPrinterError(const char *header, LONG io_Error):
  2084.      *
  2085.      *    Print a real error message for Printer.device errors.
  2086.      */
  2087.  
  2088. private VOID
  2089. PrintPrinterError(const char *header, LONG io_Error)
  2090. {
  2091.     char buffer[256];
  2092.     char defaultmessage[64];
  2093.     const char *errormessage;
  2094.                     
  2095.     switch (io_Error)
  2096.     {
  2097.         case PDERR_CANCEL:
  2098.             errormessage = "user cancelled print";
  2099.             break;
  2100.         case PDERR_NOTGRAPHICS:
  2101.             errormessage = "printer cannot output graphics";
  2102.             break;
  2103.         case PDERR_BADDIMENSION:
  2104.             errormessage = "print dimensions illegal";
  2105.             break;
  2106.         case PDERR_INTERNALMEMORY:
  2107.             errormessage = "no memory for internal variables";
  2108.             break;
  2109.         case PDERR_BUFFERMEMORY:
  2110.             errormessage = "no memory for print buffer";
  2111.             break;
  2112.         case IOERR_OPENFAIL:
  2113.             errormessage = "device/unit failed to open";
  2114.             break;
  2115.         case IOERR_ABORTED:
  2116.             errormessage = "request terminated early [after AbortIO()]";
  2117.             break;
  2118.         case IOERR_NOCMD:
  2119.             errormessage = "command not supported by device";
  2120.             break;
  2121.         case IOERR_BADLENGTH:
  2122.             errormessage = "not a valid length (usually IO_LENGTH)";
  2123.             break;
  2124.         case IOERR_BADADDRESS:
  2125.             errormessage = "invalid address (misaligned or bad range)";
  2126.             break;
  2127.         case IOERR_UNITBUSY:
  2128.             errormessage = "device opens ok, but requested unit is busy";
  2129.             break;
  2130.         case IOERR_SELFTEST:
  2131.             errormessage = "hardware failed self-test";
  2132.             break;
  2133.         default:
  2134.             sprintf(defaultmessage, "unknown I/O error #%ld", io_Error);
  2135.             errormessage = defaultmessage;
  2136.             break;
  2137.     }
  2138.     sprintf(buffer, "%s (%s)\n", header, errormessage);
  2139.     eprintf(buffer);
  2140. }
  2141.  
  2142.     /* Simple routine to call the cleanup routine of a device,
  2143.      * all devices are smart enough to handle shutdown in
  2144.      * case they have not been opened yet.
  2145.      */
  2146.  
  2147. private void 
  2148. close_device(gx_device_amiga *dev)
  2149. {
  2150. //      if(xdev -> std_procs . close_device)
  2151. //          (*xdev -> std_procs . close_device)((gx_device *)dev);
  2152.     if( dev_proc( xdev, close_device ) )
  2153.         (*(dev_proc( xdev, close_device )))((gx_device *)dev );
  2154. }
  2155.  
  2156.     /* devcleanup():
  2157.      *
  2158.      *    Clean up all devices, free all resources.
  2159.      */
  2160.  
  2161. void
  2162. devcleanup()
  2163. {
  2164.     close_device(&gs_amiga_device);
  2165.     close_device(&gs_amiga_custom_device);
  2166.     close_device(&gs_amiga_printer_device);
  2167.     close_device(&gs_amiga_ilbm_device);
  2168. }
  2169.  
  2170.     /* amiga_set_pen(gx_device *dev,gx_color_index color):
  2171.      *
  2172.      *    Sets the rendering pen and remembers the current
  2173.      *    settings.
  2174.      */
  2175.  
  2176. private VOID
  2177. amiga_set_pen(gx_device *dev,gx_color_index color)
  2178. {
  2179.     if(xdev -> last_pen != color)
  2180.         SetAPen(xdev -> rport,xdev -> last_pen = color);
  2181. }
  2182.  
  2183.     /* amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  2184.      *
  2185.      *    Map a colour either to the black or the light rendering pen.
  2186.      */
  2187.  
  2188. private gx_color_index
  2189. amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  2190. {
  2191.     if((red | green | blue) > gx_max_color_value / 2)
  2192.         return(LightPen);
  2193.     else
  2194.         return(DarkPen);
  2195. }
  2196.  
  2197.     /* amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  2198.      *
  2199.      *    Map the light/dark rendering pen to RGB values.
  2200.      */
  2201.  
  2202. private int
  2203. amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  2204. {
  2205.     int i;
  2206.  
  2207.     if(color == LightPen)
  2208.     {
  2209.         for(i = 0 ; i < 3 ; i++)
  2210.             rgb[i] = gx_max_color_value;
  2211.     }
  2212.     else
  2213.     {
  2214.         for(i = 0 ; i < 3 ; i++)
  2215.             rgb[i] = 0;
  2216.     }
  2217.  
  2218.     return(0);
  2219. }
  2220.  
  2221.     /* AllocatePens(struct ViewPort *VPort,LONG CubeSize):
  2222.      *
  2223.      *    Allocate shareable viewport pens.
  2224.      */
  2225.  
  2226. private LONG *
  2227. AllocatePens(struct ViewPort *VPort,LONG CubeSize)
  2228. {
  2229.     if(GfxBase -> LibNode . lib_Version >= 39)
  2230.     {
  2231.         LONG Total = CubeSize * CubeSize * CubeSize,*Pens;
  2232.  
  2233.         Pens = (LONG *)AllocVec(sizeof(LONG) * Total, MEMF_ANY);
  2234.         if(Pens)
  2235.         {
  2236.             LONG i,r,g,b,max = CubeSize - 1;
  2237.  
  2238.             for(i = 0 ; i < Total ; i++)
  2239.                 Pens[i] = -1;
  2240.  
  2241.             i = 0;
  2242.  
  2243.             for(r = 0 ; r < CubeSize ; r++)
  2244.             {
  2245.                 for(g = 0 ; g < CubeSize ; g++)
  2246.                 {
  2247.                     for(b = 0 ; b < CubeSize ; b++)
  2248.                     {
  2249.                         if((Pens[i++] = ObtainBestPen(VPort -> ColorMap,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max),
  2250.                             OBP_FailIfBad,    TRUE,
  2251.                             OBP_Precision,    PRECISION_IMAGE,
  2252.                         TAG_DONE)) == -1)
  2253.                         {
  2254.                             FreeVec(Pens);
  2255.  
  2256.                             return(NULL);
  2257.                         }
  2258.                     }
  2259.                 }
  2260.             }
  2261.  
  2262.             return(Pens);
  2263.         }
  2264.     }
  2265.  
  2266.     return(NULL);
  2267. }
  2268.  
  2269.     /* amiga_open_default(gx_device *dev):
  2270.      *
  2271.      *    Open the default device, i.e. a window on the Workbench screen.
  2272.      */
  2273.  
  2274. private int
  2275. amiga_open_default(gx_device *dev)
  2276. {
  2277.     struct Screen *DefaultScreen;
  2278.  
  2279.         /* Get a lock on the default public screen. */
  2280.  
  2281.     DefaultScreen = LockPubScreen(NULL);
  2282.     if(DefaultScreen)
  2283.     {
  2284.         struct DisplayInfo    DisplayInfo;
  2285.         ULONG             Mode;
  2286.  
  2287.             /* Get the default public screen display mode. */
  2288.  
  2289.         Mode = GetVPModeID(&DefaultScreen -> ViewPort);
  2290.  
  2291.             /* Inquire display mode information. */
  2292.  
  2293.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  2294.         {
  2295.             LONG    ScreenWidth,
  2296.                 ScreenHeight;
  2297.             LONG    i;
  2298.             LONG    Depth;
  2299.  
  2300.             if(GfxBase -> LibNode . lib_Version >= 39)
  2301.                 Depth = GetBitMapAttr(DefaultScreen -> RastPort . BitMap,BMA_DEPTH);
  2302.             else
  2303.                 Depth = DefaultScreen -> RastPort . BitMap -> Depth;
  2304.  
  2305.                 /* Determine screen view dimensions. */
  2306.  
  2307.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  2308.             {
  2309.                 struct ViewPortExtra *Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  2310.  
  2311.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2312.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2313.             }
  2314.             else
  2315.             {
  2316.                 struct ViewPortExtra *Extra;
  2317.  
  2318.                 Extra = (struct ViewPortExtra *)GfxLookUp(
  2319.                     &DefaultScreen -> ViewPort);
  2320.                 if(Extra)
  2321.                 {
  2322.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2323.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2324.                 }
  2325.                 else
  2326.                 {
  2327.                     ScreenWidth    = DefaultScreen -> Width;
  2328.                     ScreenHeight    = DefaultScreen -> Height;
  2329.                 }
  2330.             }
  2331.  
  2332.                 /* Adjust device to screen resolution. */
  2333.  
  2334.             if (!ResolutionSwitch)    /* Has user set -r at command line? */
  2335.             {    /* no */
  2336.  
  2337.                 /* Compute the dots_per_inch resolution from the 
  2338.                  * ticks_per_pixel resolution in the display database.
  2339.                  * See #define MAGIC_... for a comment.
  2340.                  */
  2341.  
  2342.                 if (DisplayInfo.Resolution.x && DisplayInfo.Resolution.y)
  2343.                 {
  2344.                     dev->x_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  2345.                         / DisplayInfo.Resolution.x;
  2346.                     dev->y_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  2347.                         / DisplayInfo.Resolution.y;
  2348.  
  2349.                     if (GeometrySwitch)    /* Has user set -g at command line? */
  2350.                     {    /* yes => update MediaSize to remain consistent */
  2351.                         gx_device_set_width_height(dev, dev->width, 
  2352.                             dev->height);
  2353.                     }
  2354.                     else
  2355.                     {    /* no => update width/height to remain consistent */
  2356.                         gx_device_set_media_size(dev, dev->MediaSize[0], 
  2357.                             dev->MediaSize[1]);
  2358.                     }
  2359.                 }
  2360.             }
  2361.  
  2362.                 /* Allocate a bitmap ready to be used for
  2363.                  * rendering.
  2364.                  */
  2365.  
  2366.             xdev -> super_bitmap = CreateBitMap(xdev -> width, 
  2367.                 xdev -> height, Depth, BMF_DISPLAYABLE, 
  2368.                 DefaultScreen -> RastPort . BitMap, FALSE);
  2369.             if(xdev -> super_bitmap)
  2370.             {
  2371.                     /* Clear the bitplanes. */
  2372.  
  2373.                 BltBitMap(xdev -> super_bitmap,0,0,xdev -> super_bitmap,0,0,xdev -> width,xdev -> height,0x00,(1 << xdev -> super_bitmap -> Depth) - 1,NULL);
  2374.  
  2375.                     /* Create the scroller handles. */
  2376.  
  2377.                 if(CreateScrollers(dev,DefaultScreen))
  2378.                 {
  2379.                     struct IBox ZoomBox;
  2380.  
  2381.                         /* Set up the window alternate
  2382.                          * position.
  2383.                          */
  2384.  
  2385.                     ZoomBox . Left        = 0;
  2386.                     ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  2387.                     ZoomBox . Width        = ScreenWidth;
  2388.                     ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  2389.  
  2390.                         /* Eventually, open the display window. */
  2391.  
  2392.                     xdev -> window = OpenWindowTags(NULL,
  2393.                         WA_InnerWidth,        MIN(DefaultScreen->Width / 2, 
  2394.                             xdev -> width),
  2395.                         WA_InnerHeight,        MIN(DefaultScreen->Height / 2, 
  2396.                             xdev -> height),
  2397.                         WA_CloseGadget,        TRUE,
  2398.                         WA_DepthGadget,        TRUE,
  2399.                         WA_SizeGadget,        TRUE,
  2400.                         WA_SizeBRight,        TRUE,
  2401.                         WA_SizeBBottom,        TRUE,
  2402.                         WA_Zoom,        (ULONG)(&ZoomBox),
  2403.                         WA_DragBar,        TRUE,
  2404.                         WA_NoCareRefresh,    TRUE,
  2405.                         WA_GimmeZeroZero,    TRUE,
  2406.                         WA_RMBTrap,        TRUE,
  2407.                         WA_SuperBitMap,        (ULONG)(xdev->super_bitmap),
  2408.                         WA_Gadgets,    (ULONG)(xdev->gadget[VERTICAL_SCROLLER]),
  2409.                         WA_CustomScreen,    (ULONG)DefaultScreen,
  2410.                         WA_Title,    (ULONG)"Ghostscript Amiga output window",
  2411.                         TAG_DONE);
  2412.                     if(xdev -> window)
  2413.                     {
  2414.                         xdev -> temp_rport = CreateTempRPort(
  2415.                             xdev -> window -> RPort);
  2416.                         if(xdev -> temp_rport)
  2417.                         {
  2418.                             xdev -> temp_array = (UBYTE *)AllocVec(
  2419.                                 (xdev -> window -> WScreen -> Width + 15) & ~15, 
  2420.                                 MEMF_ANY);
  2421.                             if(xdev -> temp_array)
  2422.                             {
  2423.                                 const sigset_t trapped = sigmask(SIGINT);
  2424.                                 struct Task *Task;
  2425.                                 long TaskPri;
  2426. #ifdef __PPC__
  2427.                                 struct TagItem  cttags[] = { { TASKATTR_CODE,      DispatchTask },
  2428.                                                                       { TASKATTR_NAME,      "Ghostscript window dispatcher" },
  2429.                                                                       { TASKATTR_PRI,          0                },
  2430.                                                                       { TASKATTR_STACKSIZE, 20000          },
  2431.                                                                       { TASKATTR_INHERITR2,    1                 },
  2432.                                                                       { TAG_DONE,                 0            }
  2433.                                                                     };
  2434. #endif
  2435.  
  2436.                                     /* Don't let anybody interrupt us! */
  2437. #ifdef IXEMUL
  2438.                                 sigprocmask(SIG_BLOCK,&trapped,NULL);
  2439. #endif
  2440.                                     /* Who's calling? */
  2441.  
  2442.                                 xdev -> main = (struct Process *)FindTask(NULL);
  2443.                                 
  2444.                                     /* Bring the window dispatcher task
  2445.                                      * to life with +1 priority...
  2446.                                      */
  2447.  
  2448.                                 Forbid();
  2449.  
  2450.                                 TaskPri = 1 + 
  2451.                                     xdev->main->pr_Task.tc_Node.ln_Pri;
  2452.                                 if (127 < TaskPri)    /* Ouch... */
  2453.                                     TaskPri = 127;    /* ;-) */
  2454.  
  2455. #ifdef __PPC__
  2456.                                 DispatchTaskDevice = dev;
  2457.                                 cttags[ 2 ].ti_Data = TaskPri;
  2458.                                 SetSignal(0,SIG_HANDSHAKE);
  2459.                                 Task = CreateTaskPPC( cttags );
  2460.                                 if(Task)
  2461.                                 {
  2462.                                     Wait(SIG_HANDSHAKE);
  2463.                                     Task = xdev -> dispatcher;
  2464.                                 }
  2465. #else
  2466.                                 Task = CreateTask(
  2467.                                     "Ghostscript window dispatcher",
  2468.                                     TaskPri, DispatchTask, 8192);
  2469.  
  2470.                                 Forbid();
  2471.  
  2472.                                 if(Task)
  2473.                                 {
  2474.                                         /* Cheap... */
  2475.  
  2476.                                     Task -> tc_UserData = dev;
  2477.  
  2478.                                         /* Clear the handshake bit. */
  2479.  
  2480.                                     SetSignal(0,SIG_HANDSHAKE);
  2481.  
  2482.                                         /* Wake it up. */
  2483.  
  2484.                                     Signal(Task,SIG_HANDSHAKE);
  2485.  
  2486.                                         /* Wake the task up. */
  2487.  
  2488.                                     Signal(Task,SIG_WAKEUP);
  2489.  
  2490.                                         /* Wait for the report. */
  2491.  
  2492.                                     Wait(SIG_HANDSHAKE);
  2493.  
  2494.                                         /* Get the result. */
  2495.  
  2496.                                     Task = xdev -> dispatcher;
  2497.                                 }
  2498.  
  2499.                                 Permit();
  2500. #endif
  2501.  
  2502.                                     /* Unblock signals. */
  2503. #ifdef IXEMUL
  2504.                                 sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2505. #endif
  2506.                                     /* Did we succeed in creating
  2507.                                      * the dispatcher task?
  2508.                                      */
  2509.  
  2510.                                 if(Task)
  2511.                                 {
  2512.                                     UWORD    MaxValue = 0,
  2513.                                         MinValue = 15000,
  2514.                                         Value,
  2515.                                         R,G,B;
  2516.  
  2517.                                         /* Set the window limits. */
  2518.  
  2519.                                     WindowLimits(xdev -> window,xdev -> window -> BorderLeft + MINIMUM_WIDTH + xdev -> window -> BorderRight,xdev -> window -> BorderTop + MINIMUM_HEIGHT + xdev -> window -> BorderBottom,xdev -> window -> BorderLeft + xdev -> width + xdev -> window -> BorderRight,xdev -> window -> BorderTop + xdev -> height + xdev -> window -> BorderBottom);
  2520.  
  2521.                                         /* Update the sliders. */
  2522.  
  2523.                                     WindowResize(dev);
  2524.  
  2525.                                         /* Look for the darkest and the lightest screen colours. */
  2526.  
  2527.                                     for(i = 0 ; i < MIN(xdev -> window -> WScreen -> ViewPort . ColorMap -> Count,(1 << Depth)) ; i++)
  2528.                                     {
  2529.                                         Value = GetRGB4(xdev -> window -> WScreen -> ViewPort . ColorMap,i);
  2530.  
  2531.                                         R = (Value >> 8) & 0xF;
  2532.                                         G = (Value >> 4) & 0xF;
  2533.                                         B =  Value       & 0xF;
  2534.  
  2535.                                             /* Luminance conversion included */
  2536.  
  2537.                                         Value = R * 299 + G * 588 + B * 113;
  2538.  
  2539.                                         if(Value > MaxValue)
  2540.                                         {
  2541.                                             MaxValue = Value;
  2542.  
  2543.                                             LightPen = i;
  2544.                                         }
  2545.  
  2546.                                         if(Value < MinValue)
  2547.                                         {
  2548.                                             MinValue = Value;
  2549.  
  2550.                                             DarkPen = i;
  2551.                                         }
  2552.                                     }
  2553.  
  2554.                                         /* Fill in the rest. */
  2555.  
  2556.                                     xdev -> rport    = xdev -> window -> RPort;
  2557.  
  2558.                                         /* Does the display support
  2559.                                          * at least eight colours?
  2560.                                          */
  2561.  
  2562.                                     if(Depth >= 3)
  2563.                                     {
  2564.                                         LONG cube_size,max;
  2565.  
  2566.                                             /* Set up a fitting colour cube. */
  2567.  
  2568.                                         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  2569.                                         {
  2570.                                             if((max = cube_size * cube_size * cube_size) <= 1 << Depth)
  2571.                                                 break;
  2572.                                         }
  2573.  
  2574.                                             /* Got enough colours? */
  2575.  
  2576.                                         if(cube_size != 1)
  2577.                                         {
  2578.                                             LONG *Pens;
  2579.  
  2580.                                                 /* Try to grab the cube colours,
  2581.                                                  * making a colour display.
  2582.                                                  */
  2583.  
  2584.                                             Pens = AllocatePens(&xdev -> window -> WScreen -> ViewPort,cube_size);
  2585.                                             if(Pens)
  2586.                                                 set_colour_device((gx_device_amiga *)dev,cube_size,Pens);
  2587.                                         }
  2588.                                     }
  2589.  
  2590.                                     SetBPen(xdev -> rport,0);
  2591.                                     SetDrMd(xdev -> rport,JAM2);
  2592.  
  2593.                                     amiga_set_pen(dev,DarkPen);
  2594.  
  2595.                                     UnlockPubScreen(NULL,DefaultScreen);
  2596.  
  2597.                                     return(0);
  2598.                                 }
  2599.                                 else
  2600.                                     eprintf("Ghostscript: failed to create dispatcher task\n");
  2601.                             }
  2602.                             else
  2603.                                 eprintf("Ghostscript: failed to create temporary line buffer\n");
  2604.                         }
  2605.                         else
  2606.                             eprintf("Ghostscript: failed to create temporary raster port\n");
  2607.                     }
  2608.                     else
  2609.                         eprintf("Ghostscript: failed to open window\n");
  2610.                 }
  2611.                 else
  2612.                     eprintf("Ghostscript: failed to allocate scrollers\n");
  2613.             }
  2614.             else
  2615.                 eprintf("Ghostscript: failed to allocate bitmap\n");
  2616.         }
  2617.         else
  2618.             eprintf("Ghostscript: failed to get display mode information\n");
  2619.  
  2620.         UnlockPubScreen(NULL,DefaultScreen);
  2621.     }
  2622.     else
  2623.         eprintf("Ghostscript: failed to lock default public screen\n");
  2624.  
  2625.     return_error(gs_error_unknownerror);
  2626. }
  2627.  
  2628. private int
  2629. amiga_open_custom(gx_device *dev)
  2630. {
  2631.     UBYTE    Buffer[DISPLAYNAMELEN + 1] = "";    /* see graphics/displayinfo.h */
  2632.     ULONG    ScreenID    = INVALID_ID;
  2633.     BOOL    DontTouch    = FALSE;
  2634.  
  2635.         /* Has user supplied the ID of a Display Mode? */
  2636.  
  2637.     if (1 == sscanf(xdev->display_mode, "0x%lx", &ScreenID)
  2638.         || 1 == sscanf(xdev->display_mode, "0X%lx", &ScreenID))
  2639.     {    /* yes => check wether it is available */
  2640.  
  2641.         if (ModeNotAvailable(ScreenID))
  2642.         {
  2643.             ScreenID = INVALID_ID;
  2644.         }
  2645.         else
  2646.         {
  2647.             DontTouch = TRUE;    /* Don't overwrite the env. variable. */
  2648.         }
  2649.     }
  2650.     else
  2651.     {    /* no */
  2652.  
  2653.             /* Has user supplied the name of a Display Mode? */
  2654.  
  2655.         if ('\0' != xdev->display_mode[0])
  2656.         {    /* yes */
  2657.  
  2658.             strcpy(Buffer, xdev->display_mode);
  2659.         }
  2660.         else
  2661.         {    /* no => try to read it from the environment variable */
  2662.  
  2663.             GetVar("GS_DISPLAYMODE", Buffer, sizeof (Buffer), NULL);
  2664.         }
  2665.  
  2666.         if ('\0' != Buffer[0])
  2667.         {
  2668.             UBYTE PatternBuffer[(sizeof (Buffer) * 2) + 2];
  2669.     
  2670.                 /* Set up the search pattern. */
  2671.     
  2672.             if (0 <= ParsePatternNoCase(Buffer, PatternBuffer, 
  2673.                 sizeof (PatternBuffer)))
  2674.             {
  2675.                 ULONG CurrentID = INVALID_ID;
  2676.     
  2677.                     /* Scan the entire list. */
  2678.     
  2679.                 while (INVALID_ID != (CurrentID = NextDisplayInfo(CurrentID)))
  2680.                 {
  2681.                     struct NameInfo    NameInfo;
  2682.     
  2683.                         /* Is this mode available? */
  2684.     
  2685.                     if (ModeNotAvailable(CurrentID))
  2686.                     {    /* no => continue loop */
  2687.                         continue;
  2688.                     }
  2689.     
  2690.                         /* Get the name information. */
  2691.     
  2692.                     if (GetDisplayInfoData(NULL, (UBYTE *)&NameInfo, 
  2693.                         sizeof (struct NameInfo), DTAG_NAME, CurrentID))
  2694.                     {
  2695.                             /* Does the mode name match the pattern given? */
  2696.                         if (MatchPatternNoCase(PatternBuffer, NameInfo.Name))
  2697.                         {
  2698.                             ScreenID = CurrentID;
  2699.     
  2700.                                 /* Don't overwrite the env. variable. */
  2701.     
  2702.                             DontTouch = TRUE;
  2703.                             break;
  2704.                         }
  2705.                     }
  2706.                 }
  2707.             }
  2708.         }
  2709.     }
  2710.  
  2711.     if (INVALID_ID == ScreenID && AslBase)
  2712.     {
  2713.         struct ScreenModeRequester *ScreenModeRequester;
  2714.  
  2715.         ScreenModeRequester = (struct ScreenModeRequester *)
  2716.             AllocAslRequestTags(ASL_ScreenModeRequest, TAG_DONE);
  2717.         if (ScreenModeRequester)
  2718.         {
  2719.             if (AslRequestTags(ScreenModeRequester,
  2720.                 ASLSM_TitleText,    (ULONG)"Select Ghostscript Display Mode",
  2721.                 ASLSM_MinDepth,        1,
  2722.                 ASLSM_MaxDepth,        8,
  2723.                 TAG_DONE))
  2724.             {
  2725.                 ScreenID = ScreenModeRequester->sm_DisplayID;
  2726.                 FreeAslRequest(ScreenModeRequester);
  2727.             }
  2728.             else
  2729.             {
  2730.                     /* Check wether any error occured (V38 only) */
  2731.                 
  2732.                 if (38 <= AslBase->lib_Version)
  2733.                 {
  2734.                     if (0 != IoErr())
  2735.                     {    /* yes => print additional error message */
  2736.                         eprintf("Ghostscript: failed to display screenmode "
  2737.                             "requester\n");
  2738.                     }
  2739.                 }
  2740.                  
  2741.                 /* User cancelled or IoErr() => fall back to default */
  2742.  
  2743.                 FreeAslRequest(ScreenModeRequester);
  2744.                 return (amiga_open_default(dev));
  2745.             }
  2746.         }
  2747.     }
  2748.  
  2749.         /* Is selected mode available? */
  2750.  
  2751.     if (ModeNotAvailable(ScreenID))
  2752.     {    /* no => fall back to default */
  2753.         return (amiga_open_default(dev));
  2754.     }
  2755.     else
  2756.     {    /* yes => try to open the screen */
  2757.         int result = amiga_open(dev, ScreenID);
  2758.  
  2759.             /* If successful store the name of the
  2760.              * screen mode selected.
  2761.              */
  2762.  
  2763.         if(!result && !DontTouch)
  2764.         {
  2765.             struct NameInfo    NameInfo;
  2766.  
  2767.             if (GetDisplayInfoData(NULL, (UBYTE *)&NameInfo, 
  2768.                 sizeof (struct NameInfo), DTAG_NAME, ScreenID))
  2769.             {
  2770.                 SetVar("GS_DISPLAYMODE", NameInfo.Name, -1, NULL);
  2771.             }
  2772.         }
  2773.  
  2774.         return (result);
  2775.     }
  2776. }
  2777.  
  2778.     /* amiga_open_printer(gx_device *dev):
  2779.      *
  2780.      *    Open the printer device.
  2781.      */
  2782.  
  2783. private int
  2784. amiga_open_printer(gx_device *dev)
  2785. {
  2786.     xdev->port = CreateMsgPort();
  2787.     if (xdev->port)
  2788.     {
  2789.         xdev->printer = (struct IODRPReq *)CreateIORequest(xdev->port, 
  2790.             sizeof(struct IODRPReq));
  2791.         if (xdev->printer)
  2792.         {
  2793.             if (!OpenDevice("printer.device", 0, 
  2794.                 (struct IORequest *)xdev->printer, 0))
  2795.             {
  2796.                 struct PrinterData *PD;
  2797.                 struct PrinterExtendedData *PED;
  2798.                 struct Preferences *Prefs;
  2799.  
  2800.                     /* Get the printer internal data. */
  2801.                     
  2802.                 PD = (struct PrinterData *)xdev->printer->io_Device;
  2803.                 PED    = &PD->pd_SegmentData->ps_PED;
  2804.                 Prefs = &PD->pd_Preferences;
  2805.  
  2806.                     /* Adjust device to current printer resolution. */
  2807.  
  2808.                 if (!ResolutionSwitch)    /* Has user set -r at command line? */
  2809.                 {    /* no */
  2810.                     dev->x_pixels_per_inch = (float)PED->ped_XDotsInch;
  2811.                     dev->y_pixels_per_inch = (float)PED->ped_YDotsInch;
  2812.         
  2813.                     if (GeometrySwitch)    /* Has user set -g at command line? */
  2814.                     {    /* yes => update MediaSize to remain consistent */
  2815.                         gx_device_set_width_height(dev, dev->width, 
  2816.                             dev->height);
  2817.                     }
  2818.                     else
  2819.                     {    /* no => update width/height to remain consistent */
  2820.                         gx_device_set_media_size(dev, dev->MediaSize[0], 
  2821.                             dev->MediaSize[1]);
  2822.                     }
  2823.                 }
  2824.  
  2825.                 xdev->rport = (struct RastPort *)AllocVec(
  2826.                     sizeof(struct RastPort), MEMF_ANY);
  2827.                 if (xdev->rport)
  2828.                 {
  2829.                     const sigset_t    trapped = sigmask(SIGINT);
  2830.                     struct BitMap    DummyBitMap;
  2831.                     UWORD        DummyLine[12];
  2832.  
  2833.                     InitRastPort(xdev -> rport);
  2834.  
  2835.                         /* Compensate for the non-printable are of the page:
  2836.                          * 
  2837.                          * Unfortunately the standard Amiga printer drivers 
  2838.                          * are too poorly designed for that matter and do just 
  2839.                          * provide MaxXDots/MaxYDots, which is obviously not 
  2840.                          * enough to place the image correctly on the paper.
  2841.                          * Therefore, a good approximation seems to be to 
  2842.                          * substract half of these values on either side of
  2843.                          * the bitmap. Then a SPECIAL_NOPRINT dump is 
  2844.                          * performed to see what the actual printsize in 
  2845.                          * printerpixels would be. If this reveals, that the
  2846.                          * user has set preferences to produce a smaller
  2847.                          * image the margins will be ignored for the real dump.
  2848.                          * (Of course, one could compute all this without the
  2849.                          * NOPRINT dump, it's just more convenient this way 
  2850.                          * and blames the OS for all its buggy calculations ;-)
  2851.                          *
  2852.                          * In general this provides a policy which tries to do
  2853.                          * a 1:1 dump prior to exact placement (which rules if
  2854.                          * the real non-printable margins of the printer don't
  2855.                          * fit to the estimated halves on either side).
  2856.                          *
  2857.                          * One should probably use the gs printer drivers 
  2858.                          * anyway if accuracy matters!
  2859.                          */
  2860.  
  2861. /* NOTE: Unfortunately the printer device corrects the aspect ratio based on 
  2862.  * a ModeID instead of just the supplied dimensions when a dump without 
  2863.  * SPECIAL_ASPECT is requested and ABSOLUTE_DIMENSIONS is set in preferences. 
  2864.  * Therefore it seems best to supply a ModeID which fits to the default gs 
  2865.  * device settings as well as to many printers (1:1); this may lead to wrong 
  2866.  * but expectable results in case the device resolution has a different aspect 
  2867.  * ratio.
  2868.  * TODO: Maybe the device settings could be 'normalized' to 1:1 to circumvent 
  2869.  * this problem.
  2870.  */
  2871.  
  2872.                     xdev->printer->io_Command    = PRD_DUMPRPORT;
  2873.                     xdev->printer->io_RastPort    = xdev->rport;
  2874.                     xdev->printer->io_Modes        = VGAPRODUCT_KEY;    /* 1:1 */
  2875.                     xdev->printer->io_SrcX    = 
  2876.                         MAX((LONG)(dev->width - PED->ped_MaxXDots), 0) / 2;
  2877.                     xdev->printer->io_SrcY    = PED->ped_MaxYDots ?
  2878.                         MAX((LONG)(dev->height - PED->ped_MaxYDots), 0) / 2 
  2879.                         : 0;
  2880.                     xdev->printer->io_SrcWidth    = 
  2881.                         MIN(dev->width, PED->ped_MaxXDots);
  2882.                     xdev->printer->io_SrcHeight    = PED->ped_MaxYDots ? 
  2883.                         MIN(dev->height, PED->ped_MaxYDots) : dev->height;
  2884.                     xdev->printer->io_DestCols    = xdev->printer->io_SrcWidth;
  2885.                     xdev->printer->io_DestRows    = xdev->printer->io_SrcHeight;
  2886.                     xdev->printer->io_Special    = (SPECIAL_NOPRINT);
  2887.  
  2888.                         /* Cook up a dummy bitmap to keep
  2889.                          * `smart' drivers from complaining.
  2890.                          */
  2891.  
  2892.                     InitBitMap(&DummyBitMap, 12, dev->width, dev->height);
  2893.  
  2894.                     DummyBitMap.Planes[0] = (PLANEPTR)&DummyLine;
  2895.  
  2896.                     xdev->rport->BitMap = &DummyBitMap;
  2897.  
  2898.                         /* Don't let them stop us now! */
  2899. #ifdef IXEMUL
  2900.                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2901. #endif
  2902.                         /* Ask for it... */
  2903.  
  2904.                     if(!DoIO((struct IORequest *)xdev -> printer))
  2905.                     {
  2906.                         LONG                 Depth,
  2907.                                          NumColours,
  2908.                                          CubeSize;
  2909.  
  2910.                             /* Unblock ^C signal. */
  2911. #ifdef IXEMUL
  2912.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2913. #endif
  2914.                              /* Provide everything to perform the real dump:
  2915.                               *
  2916.                               * Check wether preference settings leaded to
  2917.                               * an image smaller than the largest possible one.
  2918.                               * If this is the case the margins determined
  2919.                               * above are ignored, as the image will most 
  2920.                               * likely fit within the printable area of the
  2921.                               * page (except for those rare cases where a
  2922.                               * printout is requested whith boundaries just
  2923.                               * smaller than the largest possible ones by 
  2924.                               * values within the determined margins).
  2925.                               */
  2926.  
  2927.                         if (xdev->printer->io_DestCols 
  2928.                             < xdev->printer->io_SrcWidth)
  2929.                         {    /* reset dimensions to print the entire image */
  2930.                             xdev->printer->io_SrcX    = 0;
  2931.                             xdev->printer->io_SrcWidth    = xdev->width;
  2932.                         }
  2933.                         if (xdev->printer->io_DestRows 
  2934.                             < xdev->printer->io_SrcHeight)
  2935.                         {    /* reset dimensions to print the entire image */
  2936.                             xdev->printer->io_SrcY    = 0;
  2937.                             xdev->printer->io_SrcHeight    = xdev->height;
  2938.                         }
  2939.                         xdev->printer->io_DestCols    = 
  2940.                             xdev->printer->io_SrcWidth;
  2941.                         xdev->printer->io_DestRows    = 
  2942.                             xdev->printer->io_SrcHeight;
  2943.                         xdev->printer->io_Special    &= ~(SPECIAL_NOPRINT);
  2944.  
  2945.                             /* Set up the default colour values. */
  2946.  
  2947.                         if(Prefs -> PrintShade == SHADE_BW)
  2948.                         {
  2949.                             Depth        = 1;
  2950.                             NumColours    = 2;
  2951.                             CubeSize    = 0;
  2952.                         }
  2953.                         else
  2954.                         {
  2955.                             Depth        = 12;
  2956.                             NumColours    = 4096;
  2957.                             CubeSize    = 16;
  2958.                         }
  2959.  
  2960.                             /* Try to allocate a suitable bitmap.
  2961.                              * If an allocation fails, rescale the
  2962.                              * colour cube and bitmap depth and
  2963.                              * retry. Minimum are eight colours.
  2964.                              */
  2965.  
  2966.                         do
  2967.                         {
  2968.                                 /* Try to allocate the raster... */
  2969.  
  2970.                             xdev->bitmap = CreateBitMap(xdev->width, 
  2971.                                 xdev->height, Depth, NULL, NULL, TRUE);
  2972.                             if (!(xdev->bitmap))
  2973.                             {
  2974.                                     /* Any chance to rescale the cube? */
  2975.  
  2976.                                 if(Depth < 2)
  2977.                                     break;
  2978.                                 else
  2979.                                 {
  2980.                                         /* One plane less... */
  2981.  
  2982.                                     Depth--;
  2983.  
  2984.                                         /* Rescale the cube. */
  2985.  
  2986.                                     while(CubeSize >= 2)
  2987.                                     {
  2988.                                         NumColours = CubeSize * CubeSize 
  2989.                                             * CubeSize;
  2990.                                         if(NumColours <= (1 << Depth))
  2991.                                             break;
  2992.                                         else
  2993.                                             CubeSize--;
  2994.                                     }
  2995.  
  2996.                                         /* Less than eight colours? */
  2997.  
  2998.                                     if(CubeSize < 2)
  2999.                                         break;
  3000.                                 }
  3001.                             }
  3002.                         }
  3003.                         while(!xdev -> bitmap);
  3004.  
  3005.                             /* Got the bitmap? */
  3006.  
  3007.                         if(xdev -> bitmap)
  3008.                         {
  3009.                                 /* Allocate a suitable colour map. */
  3010.  
  3011.                             xdev -> colormap = GetColorMap(NumColours);
  3012.                             if(xdev -> colormap)
  3013.                             {
  3014.                                     /* Black & white only? */
  3015.  
  3016.                                 if(NumColours == 2)
  3017.                                 {
  3018.                                     SetRGB4CM(xdev -> colormap,0,0x0,0x0,0x0);
  3019.                                     SetRGB4CM(xdev -> colormap,1,0xF,0xF,0xF);
  3020.                                 }
  3021.                                 else
  3022.                                 {
  3023.                                     LONG i = 0,r,g,b,max = CubeSize - 1;
  3024.  
  3025.                                         /* Fill in the colour cube. */
  3026.  
  3027.                                     for(r = 0 ; r < CubeSize ; r++)
  3028.                                     {
  3029.                                         for(g = 0 ; g < CubeSize ; g++)
  3030.                                         {
  3031.                                             for(b = 0 ; b < CubeSize ; b++)
  3032.                                                 SetRGB4CM(xdev->colormap, i++, 
  3033.                                                     (15 * r) / max, 
  3034.                                                     (15 * g) / max, 
  3035.                                                     (15 * b) / max);
  3036.                                         }
  3037.                                     }
  3038.  
  3039.                                     set_colour_printer_device(
  3040.                                         (gx_device_amiga *)dev, CubeSize);
  3041.                                 }
  3042.  
  3043.                                 xdev->printer->io_ColorMap = xdev->colormap;
  3044.                                 xdev->rport->BitMap = xdev->bitmap;
  3045.  
  3046.                                 return(0);
  3047.                             }
  3048.                             else
  3049.                                 eprintf("Ghostscript: failed to allocate "
  3050.                                     "colour map\n");
  3051.                         }
  3052.                         else
  3053.                         {
  3054.                             char buffer[256];
  3055.  
  3056.                             sprintf(buffer, "Ghostscript: failed to allocate "
  3057.                                 "raster (wanted %ld, largest %ld)\n", 
  3058.                                 (dev->width + 15) / 8 * dev->height * Depth, 
  3059.                                 AvailMem(MEMF_ANY | MEMF_LARGEST));
  3060.  
  3061.                             eprintf(buffer);
  3062.                         }
  3063.                     }
  3064.                     else
  3065.                     {
  3066. #ifdef IXEMUL
  3067.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3068. #endif
  3069.                         PrintPrinterError("Ghostscript: failed to query "
  3070.                             "printer page size ", xdev->printer->io_Error);
  3071.                     }
  3072.                 }
  3073.                 else
  3074.                     eprintf("Ghostscript: failed to allocate raster port\n");
  3075.             }
  3076.             else
  3077.             {
  3078.                 PrintPrinterError("Ghostscript: printer.device ", 
  3079.                     xdev->printer->io_Error);
  3080.             }
  3081.         }
  3082.         else
  3083.             eprintf("Ghostscript: failed to allocate device driver\n");
  3084.     }
  3085.     else
  3086.         eprintf("Ghostscript: failed to create io port\n");
  3087.  
  3088.     return_error(gs_error_unknownerror);
  3089. }
  3090.  
  3091.     /* amiga_output_page_printer(gx_device *dev,int,int):
  3092.      *
  3093.      *    Send a bitmap to the printer.
  3094.      */
  3095.  
  3096. private int
  3097. amiga_output_page_printer(gx_device *dev,int num_copies,int flush)
  3098. {
  3099.     const sigset_t trapped = sigmask(SIGINT);
  3100.     int result = gs_error_unknownerror, i;
  3101.     ULONG Signals;
  3102.  
  3103.         /* We cannot possibly allow being interrupted in the middle
  3104.          * of a raster dump!
  3105.          */
  3106. #ifdef IXEMUL
  3107.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  3108. #endif
  3109.     for(i = 0 ; i < num_copies ; i++)
  3110.     {
  3111.         SetSignal(0,SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3112.  
  3113.         SendIO((struct IORequest *)xdev -> printer);
  3114.  
  3115.         Signals = Wait(SIGBREAKF_CTRL_C | (1L << xdev -> port -> mp_SigBit));
  3116.  
  3117.         if(Signals & SIGBREAKF_CTRL_C)
  3118.         {
  3119.             if(!CheckIO((struct IORequest *)xdev -> printer))
  3120.                 AbortIO((struct IORequest *)xdev -> printer);
  3121.  
  3122.             WaitIO((struct IORequest *)xdev -> printer);
  3123.  
  3124.             eprintf("Ghostscript: printing aborted\n");
  3125.  
  3126.             result = gs_error_unknownerror;
  3127.  
  3128.             break;
  3129.         }
  3130.  
  3131.         if(Signals & (1L << xdev -> port -> mp_SigBit))
  3132.         {
  3133.             if(WaitIO((struct IORequest *)xdev -> printer))
  3134.             {
  3135.                 result = gs_error_unknownerror;
  3136.  
  3137.                 PrintPrinterError("Ghostscript: failed to print raster ", 
  3138.                     xdev->printer->io_Error);
  3139.  
  3140.                 break;
  3141.             }
  3142.             else
  3143.                 result = 0;
  3144.         }
  3145.     }
  3146. #ifdef IXEMUL
  3147.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3148. #endif
  3149.  
  3150.     if (result)
  3151.         return_error(result);
  3152.     else
  3153.         return (0);
  3154. }
  3155.  
  3156.     /* amiga_close_printer(gx_device *dev):
  3157.      *
  3158.      *    Close the printer driver.
  3159.      */
  3160.  
  3161. private int
  3162. amiga_close_printer(gx_device *dev)
  3163. {
  3164.     if(xdev -> bitmap)
  3165.     {
  3166.         DeleteBitMap(xdev -> bitmap,TRUE);
  3167.  
  3168.         xdev -> bitmap = NULL;
  3169.     }
  3170.  
  3171.     if(xdev -> rport)
  3172.     {
  3173.         FreeVec(xdev -> rport);
  3174.  
  3175.         xdev -> rport = NULL;
  3176.     }
  3177.  
  3178.     if(xdev -> colormap)
  3179.     {
  3180.         FreeColorMap(xdev -> colormap);
  3181.  
  3182.         xdev -> colormap = NULL;
  3183.     }
  3184.  
  3185.     if(xdev -> printer)
  3186.     {
  3187.         if(xdev -> printer -> io_Device)
  3188.             CloseDevice((struct IORequest *)xdev -> printer);
  3189.  
  3190.         DeleteIORequest(xdev -> printer);
  3191.  
  3192.         xdev -> printer = NULL;
  3193.     }
  3194.  
  3195.     if(xdev -> port)
  3196.     {
  3197.         DeleteMsgPort(xdev -> port);
  3198.  
  3199.         xdev -> port = NULL;
  3200.     }
  3201.  
  3202.     return(0);
  3203. }
  3204.  
  3205.     /* amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data):
  3206.      *
  3207.      *    Read the raster bits into a buffer.
  3208.      */
  3209.  
  3210. private int
  3211. amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data)
  3212. {
  3213.     if(y < 0 || y > xdev -> height)
  3214.         return_error(gs_error_unknownerror);
  3215.     else
  3216.     {
  3217.         if(actual_data)
  3218.             *actual_data = (byte *)(xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y);
  3219.         else
  3220.             memcpy(str,xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y,xdev -> bitmap -> BytesPerRow);
  3221.  
  3222.         return(0);
  3223.     }
  3224. }
  3225.  
  3226.     /* amiga_open(gx_device *dev,ULONG Mode):
  3227.      *
  3228.      *    Open a custom screen.
  3229.      */
  3230.  
  3231. private int
  3232. amiga_open(gx_device *dev,ULONG Mode)
  3233. {
  3234.     struct DisplayInfo    DisplayInfo;
  3235.     struct DimensionInfo    DimensionInfo;
  3236.  
  3237.         /* Get the display dimensions. */
  3238.  
  3239.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode) && GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  3240.     {
  3241.             /* Two shades only, black & white */
  3242.  
  3243.         STATIC struct ColorSpec Colours[] =
  3244.         {
  3245.             { 0, 0x0000, 0x0000, 0x0000, },
  3246.             { 1, 0xFFFF, 0xFFFF, 0xFFFF, },
  3247.             { -1, },
  3248.         };
  3249.  
  3250.         LONG    i,cube_size,max;
  3251.         LONG    ScreenDepth;
  3252.  
  3253.             /* Start up with a maximum depth display. */
  3254.  
  3255.         ScreenDepth = DimensionInfo . MaxDepth;
  3256.  
  3257.             /* Check to see whether we will be able to
  3258.              * build a colour display or not.
  3259.              */
  3260.  
  3261.         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  3262.         {
  3263.             if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3264.                 break;
  3265.         }
  3266.  
  3267.             /* Got enough colours? */
  3268.  
  3269.         if(cube_size != 1)
  3270.             set_colour_device((gx_device_amiga *)dev,cube_size,NULL);
  3271.         else
  3272.         {
  3273.             ScreenDepth = 1;
  3274.  
  3275.             set_mono_device((gx_device_amiga *)dev);
  3276.         }
  3277.  
  3278.             /* Adjust device to screen resolution. */
  3279.  
  3280.         if (!ResolutionSwitch)    /* Has user set -r at command line? */
  3281.         {    /* no */
  3282.     
  3283.                 /* Compute the dots_per_inch resolution from the 
  3284.                  * ticks_per_pixel resolution in the display database.
  3285.                  * See #define MAGIC_... for a comment.
  3286.                  */
  3287.  
  3288.             if (DisplayInfo.Resolution.x && DisplayInfo.Resolution.y)
  3289.             {
  3290.                 dev->x_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  3291.                     / DisplayInfo.Resolution.x;
  3292.                 dev->y_pixels_per_inch = MAGIC_DPI_BASE_VALUE 
  3293.                     / DisplayInfo.Resolution.y;
  3294.  
  3295.                 if (GeometrySwitch)    /* Has user set -g at command line? */
  3296.                 {    /* yes => update MediaSize to remain consistent */
  3297.                     gx_device_set_width_height(dev, dev->width, 
  3298.                         dev->height);
  3299.                 }
  3300.                 else
  3301.                 {    /* no => update width/height to remain consistent */
  3302.                     gx_device_set_media_size(dev, dev->MediaSize[0], 
  3303.                         dev->MediaSize[1]);
  3304.                 }
  3305.             }
  3306.         }
  3307.  
  3308.             /* Ensure the computed values will fit on the screen */
  3309.             
  3310.         if (dev->width < DimensionInfo.MinRasterWidth)
  3311.             gx_device_set_width_height(dev, DimensionInfo.MinRasterWidth, 
  3312.                 dev->height);
  3313.         if (dev->width > DimensionInfo.MaxRasterWidth)
  3314.             gx_device_set_width_height(dev, DimensionInfo.MaxRasterWidth, 
  3315.                 dev->height);
  3316.         if (dev->height < DimensionInfo.MinRasterHeight)
  3317.             gx_device_set_width_height(dev, dev->width, 
  3318.                 DimensionInfo.MinRasterHeight);
  3319.         if (dev->height > DimensionInfo.MaxRasterHeight)
  3320.             gx_device_set_width_height(dev, dev->width, 
  3321.                 DimensionInfo.MaxRasterHeight);
  3322.  
  3323.             /* Try to open a custom screen; if this fails, try to
  3324.              * rescale the colour cube and retry.
  3325.              */
  3326.  
  3327.         do
  3328.         {
  3329.             xdev -> screen = OpenScreenTags(NULL,
  3330.                 SA_Depth,    ScreenDepth,
  3331.                 SA_Overscan,    OSCAN_TEXT,
  3332.                 SA_Quiet,    TRUE,
  3333.                 SA_Behind,    TRUE,
  3334.                 SA_DisplayID,    Mode,
  3335.                 SA_Colors,    (ULONG)Colours,
  3336.                 SA_AutoScroll,    TRUE,
  3337.                 SA_ShowTitle,    FALSE,
  3338.                 SA_Title,    (ULONG)"Ghostscript Amiga output screen",
  3339.                 SA_Width,    dev->width,
  3340.                 SA_Height,    dev->height,
  3341.                 TAG_DONE);
  3342.             if(!(xdev -> screen))
  3343.             {
  3344.                 if(ScreenDepth < 2)
  3345.                     break;
  3346.                 else
  3347.                 {
  3348.                     ScreenDepth--;
  3349.  
  3350.                         /* Check to see whether we will be able to
  3351.                          * build a colour display or not.
  3352.                          */
  3353.  
  3354.                     while(cube_size >= 2)
  3355.                     {
  3356.                         if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3357.                             break;
  3358.                         else
  3359.                             cube_size--;
  3360.                     }
  3361.  
  3362.                         /* Got enough colours? */
  3363.  
  3364.                     if(cube_size == 1 || ScreenDepth == 1)
  3365.                     {
  3366.                             /* Obviously not. */
  3367.  
  3368.                         ScreenDepth = 1;
  3369.  
  3370.                         set_mono_device((gx_device_amiga *)dev);
  3371.                     }
  3372.                 }
  3373.             }
  3374.         }
  3375.         while(!xdev -> screen);
  3376.  
  3377.             /* Did we succeed in opening the screen? */
  3378.  
  3379.         if(xdev -> screen)
  3380.         {
  3381.                 /* OpenScreenTags above really shouldn't have changed these,
  3382.                  * but better be safe...
  3383.                  */
  3384.                 
  3385.             gx_device_set_width_height(dev, xdev->screen->Width, 
  3386.                 xdev->screen->Height);
  3387.  
  3388.             xdev -> window = OpenWindowTags(NULL,
  3389.                 WA_Left,    0,
  3390.                 WA_Top,        0,
  3391.                 WA_Width,    dev -> width,
  3392.                 WA_Height,    dev -> height,
  3393.                 WA_Backdrop,    TRUE,
  3394.                 WA_RMBTrap,    TRUE,
  3395.                 WA_Borderless,    TRUE,
  3396.                 WA_CustomScreen,(ULONG)(xdev -> screen),
  3397.                 TAG_DONE);
  3398.             if(xdev -> window)
  3399.             {
  3400.                 xdev -> rport    = xdev -> window -> RPort;
  3401.             }
  3402.             else
  3403.             {
  3404.                 xdev -> rport    = &xdev -> screen -> RastPort;
  3405.             }
  3406.  
  3407.                 /* Establish defaults. */
  3408.  
  3409.             DarkPen        = 0;
  3410.             LightPen    = 1;
  3411.  
  3412.             SetBPen(xdev -> rport,0);
  3413.             SetDrMd(xdev -> rport,JAM2);
  3414.  
  3415.                 /* Create the temporary drawing area. */
  3416.  
  3417.             xdev -> temp_rport = CreateTempRPort(xdev -> rport);
  3418.             if(xdev -> temp_rport)
  3419.             {
  3420.                 xdev -> temp_array = (UBYTE *)AllocVec((dev -> width + 15) 
  3421.                     & ~15, MEMF_ANY);
  3422.                 if(xdev -> temp_array)
  3423.                 {
  3424.                         /* Colour output enabled? */
  3425.  
  3426.                     if(xdev -> cube_size > 0)
  3427.                     {
  3428.                         LONG r,g,b,max = xdev -> cube_size - 1;
  3429.  
  3430.                         i = 0;
  3431.  
  3432.                             /* Build a suitable colour map. */
  3433.  
  3434.                         if(GfxBase -> LibNode . lib_Version >= 39)
  3435.                         {
  3436.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3437.                             {
  3438.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3439.                                 {
  3440.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3441.                                         SetRGB32(&xdev -> screen -> ViewPort,i++,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max));
  3442.                                 }
  3443.                             }
  3444.                         }
  3445.                         else
  3446.                         {
  3447.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3448.                             {
  3449.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3450.                                 {
  3451.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3452.                                         SetRGB4(&xdev -> screen -> ViewPort,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3453.                                 }
  3454.                             }
  3455.                         }
  3456.                     }
  3457.                 }
  3458.                 else
  3459.                 {
  3460.                     eprintf("Ghostscript: failed to allocate temporary line\n");
  3461.  
  3462.                     return_error(gs_error_unknownerror);
  3463.                 }
  3464.             }
  3465.             else
  3466.             {
  3467.                 eprintf("Ghostscript: failed to allocate temporary raster\n");
  3468.  
  3469.                 return_error(gs_error_unknownerror);
  3470.             }
  3471.  
  3472.             amiga_set_pen(dev,DarkPen);
  3473.  
  3474.             return(0);
  3475.         }
  3476.         else
  3477.             eprintf("Ghostscript: failed to open screen\n");
  3478.     }
  3479.     else
  3480.         eprintf("Ghostscript: failed to get display mode information\n");
  3481.  
  3482.     return_error(gs_error_unknownerror);
  3483. }
  3484.  
  3485.     /* amiga_output_page(gx_device *dev,int,int):
  3486.      *
  3487.      *    Page is not `buffered', just bring screen/window
  3488.      *    to the front.
  3489.      */
  3490.  
  3491. private int
  3492. amiga_output_page(gx_device *dev,int num_copies,int flush)
  3493. {
  3494.     if(xdev -> screen)
  3495.         ScreenToFront(xdev -> screen);
  3496.     else
  3497.     {
  3498.         if(xdev -> window)
  3499.             WindowToFront(xdev -> window);
  3500.     }
  3501.  
  3502.     return(0);
  3503. }
  3504.  
  3505.     /* amiga_close(gx_device *dev):
  3506.      *
  3507.      *    Close the screen and free associated resources.
  3508.      */
  3509.  
  3510. private int
  3511. amiga_close(gx_device *dev)
  3512. {
  3513.     if(xdev -> dispatcher)
  3514.     {
  3515.         const sigset_t trapped = sigmask(SIGINT);
  3516. #ifdef IXEMUL
  3517.         sigprocmask(SIG_BLOCK,&trapped,NULL);
  3518. #endif
  3519.  
  3520. #ifndef __PPC__
  3521.         Forbid();
  3522.  
  3523.         Signal(xdev -> dispatcher,SIG_KILL);
  3524.  
  3525.         SetSignal(0,SIG_HANDSHAKE);
  3526.  
  3527.         Wait(SIG_HANDSHAKE);
  3528.  
  3529.         Permit();
  3530. #else
  3531.         Signal(xdev -> dispatcher,SIG_KILL);
  3532. #endif
  3533.  
  3534. #ifdef IXEMUL
  3535.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3536. #endif
  3537.     }
  3538.  
  3539.     if(xdev -> temp_array)
  3540.     {
  3541.         FreeVec(xdev -> temp_array);
  3542.  
  3543.         xdev -> temp_array = NULL;
  3544.     }
  3545.  
  3546.     if(xdev -> pens)
  3547.     {
  3548.         LONG i;
  3549.  
  3550.         for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  3551.         {
  3552.             if(xdev -> pens[i] != -1)
  3553.                 ReleasePen(xdev -> window -> WScreen -> ViewPort . ColorMap,xdev -> pens[i]);
  3554.         }
  3555.  
  3556.         FreeVec(xdev -> pens);
  3557.  
  3558.         xdev -> pens = NULL;
  3559.     }
  3560.  
  3561.     if(xdev -> temp_rport)
  3562.     {
  3563.         DeleteTempRPort(xdev -> temp_rport);
  3564.  
  3565.         xdev -> temp_rport = NULL;
  3566.     }
  3567.  
  3568.     if(xdev -> window)
  3569.     {
  3570.         CloseWindow(xdev -> window);
  3571.  
  3572.         xdev -> window = NULL;
  3573.     }
  3574.  
  3575.     DeleteScrollers(dev);
  3576.  
  3577.     if(xdev -> super_bitmap)
  3578.     {
  3579.         DeleteBitMap(xdev -> super_bitmap,FALSE);
  3580.  
  3581.         xdev -> super_bitmap = NULL;
  3582.     }
  3583.  
  3584.     if(xdev -> screen)
  3585.     {
  3586.         CloseScreen(xdev -> screen);
  3587.  
  3588.         xdev -> screen = NULL;
  3589.     }
  3590.  
  3591.     return(0);
  3592. }
  3593.  
  3594.     /* amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color):
  3595.      *
  3596.      *    Fill a rectangle with a given colour. This one is simple as it can
  3597.      *    be done with the Amiga graphics primitives.
  3598.      */
  3599.  
  3600. private int
  3601. amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3602. {
  3603.     fit_fill(dev, x, y, w, h);
  3604.     if(color != gx_no_color_index)
  3605.     {
  3606.         amiga_set_pen(dev,color);
  3607.  
  3608.         RectFill(xdev -> rport, x, y, (x + w - 1), (y + h - 1));
  3609.     }
  3610.  
  3611.     return(0);
  3612. }
  3613.  
  3614.     /* amiga_copy_mono():
  3615.      *
  3616.      *    Copy a monochrome image. This operation requires a bit of work as
  3617.      *    we cannot simply blit the image into the bitmap.
  3618.      */
  3619.  
  3620. private int
  3621. amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3622. {
  3623.     LONG i,j;
  3624.  
  3625.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3626.  
  3627.     if(zero == gx_no_color_index)
  3628.     {
  3629.         if(one != gx_no_color_index)
  3630.         {
  3631.             do
  3632.             {
  3633.                 ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3634.  
  3635.                 for(i = sourcex, j = 0 ; i < sourcex + w ; i++, j++)
  3636.                 {
  3637.                     if(base[i >> 3] & shift[i & 7])
  3638.                         xdev -> temp_array[j] = one;
  3639.                 }
  3640.  
  3641.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3642.  
  3643.                 base += raster;
  3644.  
  3645.                 y++;
  3646.             }
  3647.             while(--h);
  3648.         }
  3649.     }
  3650.     else
  3651.     {
  3652.         if(one == gx_no_color_index)
  3653.         {
  3654.             do
  3655.             {
  3656.                 ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3657.  
  3658.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3659.                 {
  3660.                     if(!(base[i >> 3] & shift[i & 7]))
  3661.                         xdev -> temp_array[j] = zero;
  3662.                 }
  3663.  
  3664.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3665.  
  3666.                 base += raster;
  3667.  
  3668.                 y++;
  3669.             }
  3670.             while(--h);
  3671.         }
  3672.         else
  3673.         {
  3674.             do
  3675.             {
  3676.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3677.                 {
  3678.                     if(base[i >> 3] & shift[i & 7])
  3679.                         xdev -> temp_array[j] = one;
  3680.                     else
  3681.                         xdev -> temp_array[j] = zero;
  3682.                 }
  3683.  
  3684.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3685.  
  3686.                 base += raster;
  3687.  
  3688.                 y++;
  3689.             }
  3690.             while(--h);
  3691.         }
  3692.     }
  3693.  
  3694.     return(0);
  3695. }
  3696.  
  3697.     /* amiga_copy_color():
  3698.      *
  3699.      *    Copy a color image (oh well...). This is just the same as the
  3700.      *    copy_mono() routine.
  3701.      */
  3702.  
  3703. private int
  3704. amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3705. {
  3706.     LONG i,j;
  3707.  
  3708.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3709.  
  3710.     do
  3711.     {
  3712.         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3713.         {
  3714.             if(base[i >> 3] & shift[i & 7])
  3715.                 xdev -> temp_array[j] = DarkPen;
  3716.             else
  3717.                 xdev -> temp_array[j] = LightPen;
  3718.         }
  3719.  
  3720.         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3721.  
  3722.         base += raster;
  3723.  
  3724.         y++;
  3725.     }
  3726.     while(--h);
  3727.  
  3728.     return(0);
  3729. }
  3730.  
  3731.     /* amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color):
  3732.      *
  3733.      *    Draw a line between two points. This one is easy as it can be done
  3734.      *    with the Amiga graphics primitives, the only glitch is having to reset
  3735.      *    the last dot to its original colour.
  3736.      */
  3737.  
  3738. private int
  3739. amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color)
  3740. {
  3741.     if(color != gx_no_color_index && (x0 != x1 || y0 != y1))
  3742.     {
  3743.         LONG pen;
  3744.  
  3745.         pen = ReadPixel(xdev -> rport,x1,y1);
  3746.  
  3747.         amiga_set_pen(dev,color);
  3748.  
  3749.         Move(xdev -> rport,x0,y0);
  3750.         Draw(xdev -> rport,x1,y1);
  3751.  
  3752.         if(pen == color)
  3753.         {
  3754.             amiga_set_pen(dev,pen);
  3755.  
  3756.             WritePixel(xdev -> rport,x1,y1);
  3757.         }
  3758.     }
  3759.  
  3760.     return(0);
  3761. }
  3762.  
  3763.     /* amiga_copy_mono_raw():
  3764.      *
  3765.      *    Copy a monochrome image to a bitmap. Just watch the
  3766.      *    astounding number of case switches.
  3767.      */
  3768.  
  3769. private int
  3770. amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3771. {
  3772.     LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3773.     UBYTE *line;
  3774.  
  3775.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3776.  
  3777.     w += sourcex;
  3778.  
  3779.     line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3780.  
  3781.     if(zero == gx_no_color_index)
  3782.     {
  3783.         if(one != gx_no_color_index)
  3784.         {
  3785.             if(one)
  3786.             {
  3787.                 do
  3788.                 {
  3789.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3790.                     {
  3791.                         if(base[i >> 3] & shift[i & 7])
  3792.                             line[j >> 3] |= shift[j & 7];
  3793.                     }
  3794.  
  3795.                     base += raster;
  3796.  
  3797.                     line += modulo;
  3798.                 }
  3799.                 while(--h);
  3800.             }
  3801.             else
  3802.             {
  3803.                 do
  3804.                 {
  3805.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3806.                     {
  3807.                         if(base[i >> 3] & shift[i & 7])
  3808.                             line[j >> 3] &= masks[j & 7];
  3809.                     }
  3810.                         base += raster;
  3811.                         line += modulo;
  3812.                 }
  3813.                 while(--h);
  3814.             }
  3815.         }
  3816.     }
  3817.     else
  3818.     {
  3819.         if(one == gx_no_color_index)
  3820.         {
  3821.             if(zero)
  3822.             {
  3823.                 do
  3824.                 {
  3825.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3826.                     {
  3827.                         if(!(base[i >> 3] & shift[i & 7]))
  3828.                             line[j >> 3] |= shift[j & 7];
  3829.                     }
  3830.  
  3831.                     base += raster;
  3832.  
  3833.                     line += modulo;
  3834.                 }
  3835.                 while(--h);
  3836.             }
  3837.             else
  3838.             {
  3839.                 do
  3840.                 {
  3841.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3842.                     {
  3843.                         if(!(base[i >> 3] & shift[i & 7]))
  3844.                             line[j >> 3] &= masks[j & 7];
  3845.                     }
  3846.  
  3847.                     base += raster;
  3848.  
  3849.                     line += modulo;
  3850.                 }
  3851.                 while(--h);
  3852.             }
  3853.         }
  3854.         else
  3855.         {
  3856.             if(one)
  3857.             {
  3858.                 do
  3859.                 {
  3860.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3861.                     {
  3862.                         if(base[i >> 3] & shift[i & 7])
  3863.                             line[j >> 3] |= shift[j & 7];
  3864.                         else
  3865.                             line[j >> 3] &= masks[j & 7];
  3866.                     }
  3867.  
  3868.                     base += raster;
  3869.  
  3870.                     line += modulo;
  3871.                 }
  3872.                 while(--h);
  3873.             }
  3874.             else
  3875.             {
  3876.                 do
  3877.                 {
  3878.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  3879.                     {
  3880.                         if(base[i >> 3] & shift[i & 7])
  3881.                             line[j >> 3] &= masks[j & 7];
  3882.                         else
  3883.                             line[j >> 3] |= shift[j & 7];
  3884.                     }
  3885.  
  3886.                     base += raster;
  3887.  
  3888.                     line += modulo;
  3889.                 }
  3890.                 while(--h);
  3891.             }
  3892.         }
  3893.     }
  3894.  
  3895.     return(0);
  3896. }
  3897.  
  3898.     /* amiga_copy_color_raw():
  3899.      *
  3900.      *    Copy a color image (oh well...). This is just the same as the
  3901.      *    copy_mono() routine.
  3902.      */
  3903.  
  3904. private int
  3905. amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3906. {
  3907.     LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3908.     UBYTE *line;
  3909.  
  3910.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  3911.  
  3912.     line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3913.  
  3914.     w += sourcex;
  3915.  
  3916.     do
  3917.     {
  3918.         for(i = sourcex, j = x ; i < w ; i++, j++)
  3919.         {
  3920.             if(base[i >> 3] & shift[i & 7])
  3921.                 line[j >> 3] |= shift[j & 7];
  3922.             else
  3923.                 line[j >> 3] &= masks[j & 7];
  3924.         }
  3925.  
  3926.         base += raster;
  3927.  
  3928.         line += modulo;
  3929.     }
  3930.     while(--h);
  3931.  
  3932.     return(0);
  3933. }
  3934.  
  3935.     /* amiga_fill_rectangle_raw():
  3936.      *
  3937.      *    Fill a rectangular area in a bitmap.
  3938.      */
  3939.  
  3940. private int
  3941. amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3942. {
  3943.     fit_fill(dev, x, y, w, h);
  3944.  
  3945.     if(color != gx_no_color_index)
  3946.     {
  3947.         UBYTE *line,startmask,endmask;
  3948.         LONG right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3949.  
  3950.         right    = x + w;
  3951.         mid    = (right >> 3) - (x >> 3);
  3952.         line    = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow + (x >> 3);
  3953.  
  3954.         x    &= 7;
  3955.         right    &= 7;
  3956.  
  3957.         if(color)
  3958.         {
  3959.             startmask    = 0xFF >> x;
  3960.             endmask        = ~(0xFF >> right);
  3961.  
  3962.             if(mid)
  3963.             {
  3964.                 UBYTE *ptr;
  3965.                 int i;
  3966.  
  3967.                 do
  3968.                 {
  3969.                     ptr = line;
  3970.  
  3971.                     *ptr++ |= startmask;
  3972.  
  3973.                     i = mid;
  3974.  
  3975.                     while(--i > 0)
  3976.                         *ptr++ = 0xFF;
  3977.  
  3978.                     *ptr |= endmask;
  3979.  
  3980.                     line += modulo;
  3981.                 }
  3982.                 while(--h);
  3983.             }
  3984.             else
  3985.             {
  3986.                 startmask &= endmask;
  3987.  
  3988.                 do
  3989.                 {
  3990.                     *line |= startmask;
  3991.  
  3992.                     line += modulo;
  3993.                 }
  3994.                 while(--h);
  3995.             }
  3996.         }
  3997.         else
  3998.         {
  3999.             startmask    = ~(0xFF >> x);
  4000.             endmask        = 0xFF >> right;
  4001.  
  4002.             if(mid)
  4003.             {
  4004.                 UBYTE *ptr;
  4005.                 LONG i;
  4006.  
  4007.                 do
  4008.                 {
  4009.                     ptr = line;
  4010.  
  4011.                     *ptr++ &= startmask;
  4012.  
  4013.                     i = mid;
  4014.  
  4015.                     while(--i > 0)
  4016.                         *ptr++ = 0x00;
  4017.  
  4018.                     *ptr &= endmask;
  4019.  
  4020.                     line += modulo;
  4021.                 }
  4022.                 while(--h);
  4023.             }
  4024.             else
  4025.             {
  4026.                 startmask |= endmask;
  4027.  
  4028.                 do
  4029.                 {
  4030.                     *line &= startmask;
  4031.  
  4032.                     line += modulo;
  4033.                 }
  4034.                 while(--h);
  4035.             }
  4036.         }
  4037.     }
  4038.  
  4039.     return(0);
  4040. }
  4041.  
  4042.     /* amiga_draw_line_raw():
  4043.      *
  4044.      *    Draw a hair line, your basic DDA algorithm;
  4045.      *    keep your fingers crossed.
  4046.      */
  4047.  
  4048. private int
  4049. amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  4050. {
  4051.     if(color != gx_no_color_index && (x != x1 || y != y1))
  4052.     {
  4053.         short xstep,ystep,dx,dy,diff,modulo;
  4054.         UBYTE *line,*plane,pen;
  4055.         LONG last;
  4056.  
  4057.         modulo    = xdev -> rport -> BitMap -> BytesPerRow;
  4058.         plane    = xdev -> rport -> BitMap -> Planes[0];
  4059.  
  4060.         line    = &plane[y1 * modulo];
  4061.         last    = y1;
  4062.         pen    = line[x1 >> 3] & (x1 & 7);
  4063.  
  4064.         dx = x1 - x;
  4065.         dy = y1 - y;
  4066.  
  4067.         if(dx < 0)
  4068.         {
  4069.             dx = -dx;
  4070.             dy = -dy;
  4071.  
  4072.             x = x1;
  4073.             y = y1;
  4074.         }
  4075.  
  4076.         if(y != last)
  4077.             line = &plane[(last = y) * modulo];
  4078.  
  4079.         if(color)
  4080.         {
  4081.             line[x >> 3] |= shift[x & 7];
  4082.  
  4083.             xstep = ystep = 0;
  4084.  
  4085.             if(dy < 0)
  4086.             {
  4087.                 if(dx > -dy)
  4088.                 {
  4089.                     diff = -dx / 2;
  4090.  
  4091.                     do
  4092.                     {
  4093.                         xstep++;
  4094.  
  4095.                         if(diff > 0)
  4096.                         {
  4097.                             ystep--;
  4098.  
  4099.                             diff = diff - dy - dx;
  4100.                         }
  4101.                         else
  4102.                             diff -= dy;
  4103.  
  4104.                         {
  4105.                             LONG x1 = x + xstep,y1 = y + ystep;
  4106.  
  4107.                             if(y1 != last)
  4108.                                 line = &plane[(last = y1) * modulo];
  4109.  
  4110.                             line[x1 >> 3] |= shift[x1 & 7];
  4111.                         }
  4112.                     }
  4113.                     while(xstep < dx);
  4114.                 }
  4115.                 else
  4116.                 {
  4117.                     if(dx == -dy)
  4118.                         diff = 0;
  4119.                     else
  4120.                         diff = -dy / 2;
  4121.  
  4122.                     do
  4123.                     {
  4124.                         ystep--;
  4125.  
  4126.                         if(diff > 0)
  4127.                             diff -= dx;
  4128.                         else
  4129.                         {
  4130.                             xstep++;
  4131.  
  4132.                             diff = diff - dy - dx;
  4133.                         }
  4134.  
  4135.                         {
  4136.                             LONG x1 = x + xstep,y1 = y + ystep;
  4137.  
  4138.                             if(y1 != last)
  4139.                                 line = &plane[(last = y1) * modulo];
  4140.  
  4141.                             line[x1 >> 3] |= shift[x1 & 7];
  4142.                         }
  4143.                     }
  4144.                     while(ystep > dy);
  4145.                 }
  4146.             }
  4147.             else
  4148.             {
  4149.                 if(dx > dy)
  4150.                 {
  4151.                     diff = -dx / 2;
  4152.  
  4153.                     do
  4154.                     {
  4155.                         xstep++;
  4156.  
  4157.                         if(diff > 0)
  4158.                         {
  4159.                             ystep++;
  4160.  
  4161.                             diff = diff + dy - dx;
  4162.                         }
  4163.                         else
  4164.                             diff += dy;
  4165.  
  4166.                         {
  4167.                             LONG x1 = x + xstep,y1 = y + ystep;
  4168.  
  4169.                             if(y1 != last)
  4170.                                 line = &plane[(last = y1) * modulo];
  4171.  
  4172.                             line[x1 >> 3] |= shift[x1 & 7];
  4173.                         }
  4174.                     }
  4175.                     while(xstep < dx);
  4176.                 }
  4177.                 else
  4178.                 {
  4179.                     if(dx == dy)
  4180.                         diff = 0;
  4181.                     else
  4182.                         diff = dy / 2;
  4183.  
  4184.                     do
  4185.                     {
  4186.                         ystep++;
  4187.  
  4188.                         if(diff > 0)
  4189.                             diff -= dx;
  4190.                         else
  4191.                         {
  4192.                             xstep++;
  4193.  
  4194.                             diff = diff + dy - dx;
  4195.                         }
  4196.  
  4197.                         {
  4198.                             LONG x1 = x + xstep,y1 = y + ystep;
  4199.  
  4200.                             if(y1 != last)
  4201.                                 line = &plane[(last = y1) * modulo];
  4202.  
  4203.                             line[x1 >> 3] |= shift[x1 & 7];
  4204.                         }
  4205.                     }
  4206.                     while(ystep < dy);
  4207.                 }
  4208.             }
  4209.  
  4210.             if(!pen)
  4211.             {
  4212.                 if(y1 != last)
  4213.                     line = &plane[(last = y1) * modulo];
  4214.  
  4215.                 line[x1 >> 3] &= masks[x1 & 7];
  4216.             }
  4217.         }
  4218.         else
  4219.         {
  4220.             line[x >> 3] &= masks[x & 7];
  4221.  
  4222.             xstep = ystep = 0;
  4223.  
  4224.             if(dy < 0)
  4225.             {
  4226.                 if(dx > -dy)
  4227.                 {
  4228.                     diff = -dx / 2;
  4229.  
  4230.                     do
  4231.                     {
  4232.                         xstep++;
  4233.  
  4234.                         if(diff > 0)
  4235.                         {
  4236.                             ystep--;
  4237.  
  4238.                             diff = diff - dy - dx;
  4239.                         }
  4240.                         else
  4241.                             diff -= dy;
  4242.  
  4243.                         {
  4244.                             LONG x1 = x + xstep,y1 = y + ystep;
  4245.  
  4246.                             if(y1 != last)
  4247.                                 line = &plane[(last = y1) * modulo];
  4248.  
  4249.                             line[x1 >> 3] &= masks[x1 & 7];
  4250.                         }
  4251.                     }
  4252.                     while(xstep < dx);
  4253.                 }
  4254.                 else
  4255.                 {
  4256.                     if(dx == -dy)
  4257.                         diff = 0;
  4258.                     else
  4259.                         diff = -dy / 2;
  4260.  
  4261.                     do
  4262.                     {
  4263.                         ystep--;
  4264.  
  4265.                         if(diff > 0)
  4266.                             diff -= dx;
  4267.                         else
  4268.                         {
  4269.                             xstep++;
  4270.  
  4271.                             diff = diff - dy - dx;
  4272.                         }
  4273.  
  4274.                         {
  4275.                             LONG x1 = x + xstep,y1 = y + ystep;
  4276.  
  4277.                             if(y1 != last)
  4278.                                 line = &plane[(last = y1) * modulo];
  4279.  
  4280.                             line[x1 >> 3] &= masks[x1 & 7];
  4281.                         }
  4282.                     }
  4283.                     while(ystep > dy);
  4284.                 }
  4285.             }
  4286.             else
  4287.             {
  4288.                 if(dx > dy)
  4289.                 {
  4290.                     diff = -dx / 2;
  4291.  
  4292.                     do
  4293.                     {
  4294.                         xstep++;
  4295.  
  4296.                         if(diff > 0)
  4297.                         {
  4298.                             ystep++;
  4299.  
  4300.                             diff = diff + dy - dx;
  4301.                         }
  4302.                         else
  4303.                             diff += dy;
  4304.  
  4305.                         {
  4306.                             LONG x1 = x + xstep,y1 = y + ystep;
  4307.  
  4308.                             if(y1 != last)
  4309.                                 line = &plane[(last = y1) * modulo];
  4310.  
  4311.                             line[x1 >> 3] &= masks[x1 & 7];
  4312.                         }
  4313.                     }
  4314.                     while(xstep < dx);
  4315.                 }
  4316.                 else
  4317.                 {
  4318.                     if(dx == dy)
  4319.                         diff = 0;
  4320.                     else
  4321.                         diff =  dy / 2;
  4322.  
  4323.                     do
  4324.                     {
  4325.                         ystep++;
  4326.  
  4327.                         if(diff > 0)
  4328.                             diff -= dx;
  4329.                         else
  4330.                         {
  4331.                             xstep++;
  4332.  
  4333.                             diff = diff + dy - dx;
  4334.                         }
  4335.  
  4336.                         {
  4337.                             LONG x1 = x + xstep,y1 = y + ystep;
  4338.  
  4339.                             if(y1 != last)
  4340.                                 line = &plane[(last = y1) * modulo];
  4341.  
  4342.                             line[x1 >> 3] &= masks[x1 & 7];
  4343.                         }
  4344.                     }
  4345.                     while(ystep < dy);
  4346.                 }
  4347.             }
  4348.  
  4349.             if(pen)
  4350.             {
  4351.                 if(y1 != last)
  4352.                     line = &plane[(last = y1) * modulo];
  4353.  
  4354.                 line[x1 >> 3] |= pen;
  4355.             }
  4356.         }
  4357.     }
  4358.  
  4359.     return(0);
  4360. }
  4361.  
  4362.     /* amiga_open_ilbm(gx_device *dev):
  4363.      *
  4364.      *    Open the ilbm device.
  4365.      */
  4366.  
  4367. private int
  4368. amiga_open_ilbm(gx_device *dev)
  4369. {
  4370.     xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY);
  4371.     if(xdev -> rport)
  4372.     {
  4373.         InitRastPort(xdev -> rport);
  4374.  
  4375.         xdev -> bitmap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY);
  4376.         if(xdev -> bitmap)
  4377.         {
  4378.             InitBitMap(xdev -> bitmap,1,xdev -> width,xdev -> height);
  4379.  
  4380.             xdev -> bitplane = AllocVec(xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,MEMF_ANY | MEMF_CLEAR);
  4381.             if(xdev -> bitplane)
  4382.             {
  4383.                 xdev -> bitmap -> Planes[0]    = xdev -> bitplane;
  4384.                 xdev -> rport -> BitMap        = xdev -> bitmap;
  4385.                 xdev -> page_count        = 1;
  4386.  
  4387.                 DarkPen        = 0;
  4388.                 LightPen    = 1;
  4389.  
  4390.                 return(0);
  4391.             }
  4392.             else
  4393.             {
  4394.                 char buffer[256];
  4395.  
  4396.                 sprintf(buffer,"Ghostscript: failed to allocate raster "
  4397.                     "(wanted %ld, largest %ld)\n", 
  4398.                     (long)(xdev->bitmap->Rows * xdev->bitmap->BytesPerRow),
  4399.                     AvailMem(MEMF_ANY | MEMF_LARGEST));
  4400.  
  4401.                 eprintf(buffer);
  4402.             }
  4403.         }
  4404.         else
  4405.             eprintf("Ghostscript: failed to allocate bitmap\n");
  4406.     }
  4407.     else
  4408.         eprintf("Ghostscript: failed to allocate raster port\n");
  4409.  
  4410.     return_error(gs_error_unknownerror);
  4411. }
  4412.  
  4413.     /* amiga_output_page_ilbm(gx_device *dev,int,int):
  4414.      *
  4415.      *    Send a bitmap to an IFF-ILBM file.
  4416.      */
  4417.  
  4418. private int
  4419. amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush)
  4420. {
  4421.     const sigset_t trapped = sigmask(SIGINT);
  4422.     char buffer[270];
  4423.  
  4424.     sprintf(buffer,"%s_%04d.ilbm",xdev -> file_name,xdev -> page_count);
  4425.  
  4426.     fprintf(stdout,"\n\033[ASaving page Nº%d to \"%s\"...\033[K",xdev -> page_count,buffer);
  4427.     fflush(stdout);
  4428. #ifdef IXEMUL
  4429.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  4430. #endif
  4431.     if(SaveBitMap(buffer,xdev -> bitmap,xdev -> width,xdev -> height,(UWORD)xdev -> x_pixels_per_inch,xdev -> y_pixels_per_inch))
  4432.     {
  4433.         fprintf(stdout,"\n\033[APage saved to file \"%s\".\033[K\n",buffer);
  4434.  
  4435.         xdev -> page_count++;
  4436.  
  4437. #ifdef IXEMUL
  4438.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4439. #endif
  4440.  
  4441.         return (0);
  4442.     }
  4443.     else
  4444.     {
  4445.         eprintf("\n\033[AGhostscript: error saving page\033[K");
  4446.  
  4447. #ifdef IXEMUL
  4448.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4449. #endif
  4450.  
  4451.         return_error(gs_error_unknownerror);
  4452.     }
  4453. }
  4454.  
  4455.     /* amiga_close_ilbm(gx_device *dev):
  4456.      *
  4457.      *    Close the ilbm driver.
  4458.      */
  4459.  
  4460. private int
  4461. amiga_close_ilbm(gx_device *dev)
  4462. {
  4463.     if(xdev -> bitplane)
  4464.     {
  4465.         FreeVec(xdev -> bitplane);
  4466.  
  4467.         xdev -> bitplane = NULL;
  4468.     }
  4469.  
  4470.     if(xdev -> bitmap)
  4471.     {
  4472.         FreeVec(xdev -> bitmap);
  4473.  
  4474.         xdev -> bitmap = NULL;
  4475.     }
  4476.  
  4477.     if(xdev -> rport)
  4478.     {
  4479.         FreeVec(xdev -> rport);
  4480.  
  4481.         xdev -> rport = NULL;
  4482.     }
  4483.  
  4484.     return(0);
  4485. }
  4486.  
  4487. private int
  4488. amiga_get_params(gx_device *dev,gs_param_list *plist)
  4489. {
  4490.     int code = gx_default_get_params(dev,plist);
  4491.     gs_param_string dms;
  4492.     gs_param_string ofs;
  4493.  
  4494.     dms.data = (const byte *)xdev->display_mode,
  4495.       dms.size = strlen(xdev->display_mode),
  4496.       dms.persistent = false;
  4497.  
  4498.     ofs.data = (const byte *)xdev->file_name,
  4499.       ofs.size = strlen(xdev->file_name),
  4500.       ofs.persistent = false;
  4501.  
  4502.     /* Transmit the values. */
  4503.  
  4504.     if (code < 0 
  4505.         || (code = param_write_string(plist, "DisplayMode", &dms)) < 0
  4506.         || (code = param_write_string(plist, "OutputFile", &ofs)) < 0
  4507.        )
  4508.         return code;
  4509.  
  4510.     return 0;
  4511. }
  4512.  
  4513. private int
  4514. amiga_put_params(gx_device *dev,gs_param_list *plist)
  4515. {
  4516.     int ecode = 0;
  4517.     int code;
  4518.     const char /*_ds*/ *param_name;
  4519.     gs_param_string dms;
  4520.     gs_param_string ofs;
  4521.     gs_param_float_array hwra;
  4522.     gs_param_int_array hwsa;
  4523.     
  4524.     switch ( code = param_read_string(plist, (param_name = "DisplayMode"), &dms) )
  4525.     {
  4526.     case 0:
  4527.         if ( dms.size >= (DISPLAYNAMELEN + 1) )    /* see displayinfo.h */
  4528.             ecode = gs_note_error(gs_error_limitcheck);
  4529.         else if (dms.size >= 11 && '0' == dms.data[0]    /* correct hex val? */
  4530.                 && ('x' == dms.data[1] || 'X' == dms.data[1]))
  4531.             ecode = gs_note_error(gs_error_limitcheck);
  4532.         else
  4533.             break;
  4534.         goto mide;
  4535.     default:
  4536.         ecode = code;
  4537. mide:        param_signal_error(plist, param_name, ecode);
  4538.     case 1:
  4539.         dms.data = 0;
  4540.         break;
  4541.     }
  4542.  
  4543.     switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofs) )
  4544.     {
  4545.     case 0:
  4546.         if ( ofs.size >= 256 )
  4547.           ecode = gs_note_error(gs_error_limitcheck);
  4548.         else
  4549.           break;
  4550.         goto ofe;
  4551.     default:
  4552.         ecode = code;
  4553. ofe:        param_signal_error(plist, param_name, ecode);
  4554.     case 1:
  4555.         ofs.data = 0;
  4556.         break;
  4557.     }
  4558.  
  4559.     /* Because the resolution is set after the device has been opened we need
  4560.      * to detect wether user has set -g and/or -r at the command line in 
  4561.      * order to prevent wrong computing of HWSize/MediaSize from HWResolution.
  4562.      * We therefore double the code from gsdparam.c and set global variables
  4563.      * accordingly.
  4564.      * The following code between [BEGIN] and [END ] should always double the 
  4565.      * one in gsdparam.c except those two lines marked with [ADDED].
  4566.      */
  4567.  
  4568. /* [BEGIN]: doubled code from gsdparam.c */     
  4569. #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
  4570.   switch ( code = pread(plist, (param_name = pname), &(pa)) )\
  4571.   {\
  4572.   case 0:\
  4573.     if ( (pa).size != psize )\
  4574.       ecode = gs_note_error(gs_error_rangecheck);\
  4575.     else { 
  4576. /* The body of the processing code goes here. */
  4577. /* If it succeeds, it should do a 'break'; */
  4578. /* if it fails, it should set ecode and fall through. */
  4579. #define END_ARRAY_PARAM(pa, e)\
  4580.     }\
  4581.     goto e;\
  4582.   default:\
  4583.     ecode = code;\
  4584. e:    param_signal_error(plist, param_name, ecode);\
  4585.   case 1:\
  4586.     (pa).data = 0;        /* mark as not filled */\
  4587.   }
  4588.  
  4589.     /*
  4590.      * The HWResolution, HWSize, and MediaSize parameters interact in
  4591.      * the following way:
  4592.      *    1. Setting HWResolution recomputes HWSize from MediaSize.
  4593.      *    2. Setting HWSize recomputes MediaSize from HWResolution.
  4594.      *    3. Setting MediaSize recomputes HWSize from HWResolution.
  4595.      * If more than one parameter is being set, we apply these rules
  4596.      * in the order 1, 2, 3.  This does the right thing in the most
  4597.      * common case of setting more than one parameter, namely,
  4598.      * setting both HWResolution and HWSize.
  4599.      */
  4600.  
  4601.     BEGIN_ARRAY_PARAM(param_read_float_array, "HWResolution", hwra, 2, hwre)
  4602.         if ( hwra.data[0] <= 0 || hwra.data[1] <= 0 )
  4603.           ecode = gs_note_error(gs_error_rangecheck);
  4604.         else
  4605.         {
  4606.             ResolutionSwitch = TRUE;    /* [ADDED]: user has set -r */
  4607.           break;
  4608.         }
  4609.     END_ARRAY_PARAM(hwra, hwre)
  4610.  
  4611.     BEGIN_ARRAY_PARAM(param_read_int_array, "HWSize", hwsa, 2, hwsa)
  4612.         /* We need a special check to handle the nullpage device, */
  4613.         /* whose size is legitimately [0 0]. */
  4614.         if ( (hwsa.data[0] <= 0 && hwsa.data[0] != dev->width) ||
  4615.              (hwsa.data[1] <= 0 && hwsa.data[1] != dev->height)
  4616.            )
  4617.           ecode = gs_note_error(gs_error_rangecheck);
  4618. #define max_coord (max_fixed / fixed_1)
  4619. #if max_coord < max_int
  4620.         else if ( hwsa.data[0] > max_coord || hwsa.data[1] > max_coord )
  4621.           ecode = gs_note_error(gs_error_limitcheck);
  4622. #endif
  4623. #undef max_coord
  4624.         else
  4625.         {
  4626.             GeometrySwitch = TRUE;        /* [ADDED]: user has set -g */
  4627.           break;
  4628.         }
  4629.     END_ARRAY_PARAM(hwsa, hwse)
  4630. /* [END]: doubled code from gsdparam.c */     
  4631.  
  4632.     if (ecode < 0)
  4633.         return (ecode);
  4634.     code = gx_default_put_params(dev,plist);
  4635.     if (code < 0)
  4636.         return (code);
  4637.  
  4638.     if ( dms.data != 0 )
  4639.       {    if ( dev->is_open )
  4640.           gs_closedevice(dev);
  4641.         memcpy(xdev->display_mode, dms.data, dms.size);
  4642.         xdev->display_mode[dms.size] = 0;
  4643.       }
  4644.  
  4645.     if ( ofs.data != 0 )
  4646.       {
  4647.         memcpy(xdev->file_name, ofs.data, ofs.size);
  4648.         xdev->file_name[ofs.size] = 0;
  4649.       }
  4650.     
  4651.     if (code < 0)
  4652.         return (code);    
  4653.     return (0);    
  4654. }
  4655.  
  4656.     /* amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4657.      *
  4658.      *    Turn an RGB colour into a pen index.
  4659.      */
  4660.  
  4661. private gx_color_index
  4662. amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4663. {
  4664.     LONG max = xdev -> cube_size - 1,r,g,b;
  4665.  
  4666.     r = (max * red)   / gx_max_color_value;
  4667.     g = (max * green) / gx_max_color_value;
  4668.     b = (max * blue)  / gx_max_color_value;
  4669.  
  4670.     return((r * xdev -> cube_size + g) * xdev -> cube_size + b);
  4671. }
  4672.  
  4673.     /* amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4674.      *
  4675.      *    Turn a pen index into RGB colour values.
  4676.      */
  4677.  
  4678. private int
  4679. amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4680. {
  4681.     LONG i,value,max = xdev -> cube_size - 1;
  4682.  
  4683.     for(i = 2 ; i >= 0 ; i--)
  4684.     {
  4685.         value = color % xdev -> cube_size;
  4686.  
  4687.         rgb[i] = (gx_max_color_value * value) / max;
  4688.  
  4689.         color /= xdev -> cube_size;
  4690.     }
  4691.  
  4692.     return(0);
  4693. }
  4694.  
  4695.     /* amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4696.      *
  4697.      *    Turn an RGB colour into a pen index; this routine takes remapped
  4698.      *    pens into account.
  4699.      */
  4700.  
  4701. private gx_color_index
  4702. amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4703. {
  4704.     LONG max = xdev -> cube_size - 1,r,g,b;
  4705.  
  4706.     r = (max * red)   / gx_max_color_value;
  4707.     g = (max * green) / gx_max_color_value;
  4708.     b = (max * blue)  / gx_max_color_value;
  4709.  
  4710.     return(xdev -> pens[(r * xdev -> cube_size + g) * xdev -> cube_size + b]);
  4711. }
  4712.  
  4713.     /* amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4714.      *
  4715.      *    Turn a pen index into RGB colour values; this routine takes remapped
  4716.      *    pens into account.
  4717.      */
  4718.  
  4719. private int
  4720. amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4721. {
  4722.     LONG i,value,max = xdev -> cube_size - 1;
  4723.  
  4724.         /* Find the matching pen... */
  4725.  
  4726.     for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  4727.     {
  4728.         if(xdev -> pens[i] == color)
  4729.         {
  4730.             color = i;
  4731.  
  4732.             break;
  4733.         }
  4734.     }
  4735.  
  4736.     for(i = 2 ; i >= 0 ; i--)
  4737.     {
  4738.         value = color % xdev -> cube_size;
  4739.  
  4740.         rgb[i] = (gx_max_color_value * value) / max;
  4741.  
  4742.         color /= xdev -> cube_size;
  4743.     }
  4744.  
  4745.     return(0);
  4746. }
  4747.  
  4748.     /* amiga_copy_color8():
  4749.      *
  4750.      *    Copy a color image, the source is guaranteed to consist of
  4751.      *    one byte per colour.
  4752.      */
  4753.  
  4754. private int
  4755. amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4756. {
  4757.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4758.  
  4759.     base += sourcex;
  4760.  
  4761.     if(w > xdev -> width)
  4762.         w = xdev -> width;
  4763.  
  4764.     do
  4765.     {
  4766.         CopyMem((UBYTE *)base,xdev -> temp_array,w);
  4767.  
  4768.         WritePixelLine8(xdev -> rport,x,y++,w,xdev -> temp_array,xdev -> temp_rport);
  4769.  
  4770.         base += raster;
  4771.     }
  4772.     while(--h);
  4773.  
  4774.     return(0);
  4775. }
  4776.  
  4777.     /* amiga_copy_mono_raw_color():
  4778.      *
  4779.      *    Copy a monochrome image to a bitmap.
  4780.      */
  4781.  
  4782. private int
  4783. amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  4784. {
  4785.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4786.  
  4787.     if(zero != gx_no_color_index && one != gx_no_color_index)
  4788.     {
  4789.         PLANEPTR line[12];
  4790.         LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4791.  
  4792.         for(i = 0 ; i < depth ; i++)
  4793.             line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4794.  
  4795.         w += sourcex;
  4796.  
  4797.         if(zero == gx_no_color_index)
  4798.         {
  4799.             do
  4800.             {
  4801.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4802.                 {
  4803.                     if(base[i >> 3] & shift[i & 7])
  4804.                     {
  4805.                         for(k = 0 ; k < depth ; k++)
  4806.                         {
  4807.                             if(one & (1 << k))
  4808.                                 line[k][j >> 3] |= shift[j & 7];
  4809.                             else
  4810.                                 line[k][j >> 3] &= masks[j & 7];
  4811.                         }
  4812.                     }
  4813.                 }
  4814.  
  4815.                 base += raster;
  4816.  
  4817.                 for(k = 0 ; k < depth ; k++)
  4818.                     line[k] += modulo;
  4819.             }
  4820.             while(--h);
  4821.         }
  4822.         else
  4823.         {
  4824.             if(one == gx_no_color_index)
  4825.             {
  4826.                 do
  4827.                 {
  4828.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4829.                     {
  4830.                         if(base[i >> 3] & shift[i & 7])
  4831.                         {
  4832.                             for(k = 0 ; k < depth ; k++)
  4833.                             {
  4834.                                 if(zero & (1 << k))
  4835.                                     line[k][j >> 3] |= shift[j & 7];
  4836.                                 else
  4837.                                     line[k][j >> 3] &= masks[j & 7];
  4838.                             }
  4839.                         }
  4840.                     }
  4841.  
  4842.                     base += raster;
  4843.  
  4844.                     for(k = 0 ; k < depth ; k++)
  4845.                         line[k] += modulo;
  4846.                 }
  4847.                 while(--h);
  4848.             }
  4849.             else
  4850.             {
  4851.                 do
  4852.                 {
  4853.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4854.                     {
  4855.                         if(base[i >> 3] & shift[i & 7])
  4856.                         {
  4857.                             for(k = 0 ; k < depth ; k++)
  4858.                             {
  4859.                                 if(one & (1 << k))
  4860.                                     line[k][j >> 3] |= shift[j & 7];
  4861.                                 else
  4862.                                     line[k][j >> 3] &= masks[j & 7];
  4863.                             }
  4864.                         }
  4865.                         else
  4866.                         {
  4867.                             for(k = 0 ; k < depth ; k++)
  4868.                             {
  4869.                                 if(zero & (1 << k))
  4870.                                     line[k][j >> 3] |= shift[j & 7];
  4871.                                 else
  4872.                                     line[k][j >> 3] &= masks[j & 7];
  4873.                             }
  4874.                         }
  4875.                     }
  4876.  
  4877.                     base += raster;
  4878.  
  4879.                     for(k = 0 ; k < depth ; k++)
  4880.                         line[k] += modulo;
  4881.                 }
  4882.                 while(--h);
  4883.             }
  4884.         }
  4885.     }
  4886.  
  4887.     return(0);
  4888. }
  4889.  
  4890.     /* amiga_copy_color_raw_color16():
  4891.      *
  4892.      *    Copy a color image, the source data is guaranteed to consist
  4893.      *    of one word per colour.
  4894.      */
  4895.  
  4896. private int
  4897. amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4898. {
  4899.     PLANEPTR line[12];
  4900.     LONG i,j,k;
  4901.     LONG modulo = xdev->rport->BitMap->BytesPerRow;
  4902.     LONG depth = xdev->rport->BitMap->Depth;
  4903.     UWORD *wordbase = (UWORD *)base;
  4904.  
  4905.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  4906.  
  4907.     for(i = 0 ; i < depth ; i++)
  4908.         line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4909.  
  4910.         w += sourcex;
  4911.  
  4912.     raster /= 2;
  4913.  
  4914.     do
  4915.     {
  4916.         for(i = sourcex, j = x ; i < w ; i++, j++)
  4917.         {
  4918.             for(k = 0 ; k < depth ; k++)
  4919.             {
  4920.                 if(wordbase[i] & (1 << k))
  4921.                     line[k][j >> 3] |= shift[j & 7];
  4922.                 else
  4923.                     line[k][j >> 3] &= masks[j & 7];
  4924.             }
  4925.         }
  4926.  
  4927.         wordbase += raster;
  4928.  
  4929.         for(k = 0 ; k < depth ; k++)
  4930.             line[k] += modulo;
  4931.     }
  4932.     while(--h);
  4933.  
  4934.     return(0);
  4935. }
  4936.  
  4937.     /* amiga_fill_rectangle_raw_color():
  4938.      *
  4939.      *    Fill a rectangular area in a bitmap.
  4940.      */
  4941.  
  4942. private int
  4943. amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4944. {
  4945.     fit_fill(dev, x, y, w, h);
  4946.  
  4947.     if(color != gx_no_color_index)
  4948.     {
  4949.         PLANEPTR line[12];
  4950.         LONG i,j,right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4951.  
  4952.         for(i = 0 ; i < depth ; i++)
  4953.             line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo + (x >> 3);
  4954.  
  4955.         right    = x + w;
  4956.         mid    = (right >> 3) - (x >> 3);
  4957.  
  4958.         x    &= 7;
  4959.         right    &= 7;
  4960.  
  4961.         if(mid)
  4962.         {
  4963.             UBYTE *ptr;
  4964.  
  4965.             do
  4966.             {
  4967.                 for(j = 0 ; j < depth ; j++)
  4968.                 {
  4969.                     ptr = line[j];
  4970.  
  4971.                     i = mid;
  4972.  
  4973.                     if(color & (1 << j))
  4974.                     {
  4975.                         *ptr++ |= 0xFF >> x;
  4976.  
  4977.                         while(--i > 0)
  4978.                             *ptr++ = 0xFF;
  4979.  
  4980.                         *ptr |= ~(0xFF >> right);
  4981.                     }
  4982.                     else
  4983.                     {
  4984.                         *ptr++ &= ~(0xFF >> x);
  4985.  
  4986.                         while(--i > 0)
  4987.                             *ptr++ = 0x00;
  4988.  
  4989.                         *ptr &= 0xFF >> right;
  4990.                     }
  4991.  
  4992.                     line[j] += modulo;
  4993.                 }
  4994.             }
  4995.             while(--h);
  4996.         }
  4997.         else
  4998.         {
  4999.             UBYTE    one_mask    = (0xFF >> x) & ~(0xFF >> right),
  5000.                 zero_mask    = ~(0xFF >> x) | (0xFF >> right);
  5001.  
  5002.             do
  5003.             {
  5004.                 for(j = 0 ; j < depth ; j++)
  5005.                 {
  5006.                     if(color & (1 << j))
  5007.                         *line[j] |= one_mask;
  5008.                     else
  5009.                         *line[j] &= zero_mask;
  5010.  
  5011.                     line[j] += modulo;
  5012.                 }
  5013.             }
  5014.             while(--h);
  5015.         }
  5016.     }
  5017.  
  5018.     return(0);
  5019. }
  5020.  
  5021.     /* amiga_draw_line_raw_color():
  5022.      *
  5023.      *    Draw a hair line, your basic DDA algorithm;
  5024.      *    keep your fingers crossed.
  5025.      */
  5026.  
  5027. private int
  5028. amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  5029. {
  5030.     if(color != gx_no_color_index && (x != x1 || y != y1))
  5031.     {
  5032.         LONG xstep,ystep,dx,dy,diff,modulo;
  5033.         UBYTE *line,*plane,pen;
  5034.         LONG last,i,orig_x = x,orig_y = y;
  5035.  
  5036.         modulo = xdev -> rport -> BitMap -> BytesPerRow;
  5037.  
  5038.         for(i = 0 ; i < xdev -> rport -> BitMap -> Depth ; i++)
  5039.         {
  5040.             plane    = xdev -> rport -> BitMap -> Planes[i];
  5041.             line    = &plane[y1 * modulo];
  5042.             last    = y1;
  5043.             pen    = line[x1 >> 3] & (x1 & 7);
  5044.             x    = orig_x;
  5045.             y    = orig_y;
  5046.  
  5047.             dx = x1 - x;
  5048.             dy = y1 - y;
  5049.  
  5050.             if(dx < 0)
  5051.             {
  5052.                 dx = -dx;
  5053.                 dy = -dy;
  5054.  
  5055.                 x = x1;
  5056.                 y = y1;
  5057.             }
  5058.  
  5059.             if(y != last)
  5060.                 line = &plane[(last = y) * modulo];
  5061.  
  5062.             if(color & (1 << i))
  5063.             {
  5064.                 line[x >> 3] |= shift[x & 7];
  5065.  
  5066.                 xstep = ystep = 0;
  5067.  
  5068.                 if(dy < 0)
  5069.                 {
  5070.                     if(dx > -dy)
  5071.                     {
  5072.                         diff = -dx / 2;
  5073.  
  5074.                         do
  5075.                         {
  5076.                             xstep++;
  5077.  
  5078.                             if(diff > 0)
  5079.                             {
  5080.                                 ystep--;
  5081.  
  5082.                                 diff = diff - dy - dx;
  5083.                             }
  5084.                             else
  5085.                                 diff -= dy;
  5086.  
  5087.                             {
  5088.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5089.  
  5090.                                 if(y1 != last)
  5091.                                     line = &plane[(last = y1) * modulo];
  5092.  
  5093.                                 line[x1 >> 3] |= shift[x1 & 7];
  5094.                             }
  5095.                         }
  5096.                         while(xstep < dx);
  5097.                     }
  5098.                     else
  5099.                     {
  5100.                         if(dx == -dy)
  5101.                             diff = 0;
  5102.                         else
  5103.                             diff = -dy / 2;
  5104.  
  5105.                         do
  5106.                         {
  5107.                             ystep--;
  5108.  
  5109.                             if(diff > 0)
  5110.                                 diff -= dx;
  5111.                             else
  5112.                             {
  5113.                                 xstep++;
  5114.  
  5115.                                 diff = diff - dy - dx;
  5116.                             }
  5117.  
  5118.                             {
  5119.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5120.  
  5121.                                 if(y1 != last)
  5122.                                     line = &plane[(last = y1) * modulo];
  5123.  
  5124.                                 line[x1 >> 3] |= shift[x1 & 7];
  5125.                             }
  5126.                         }
  5127.                         while(ystep > dy);
  5128.                     }
  5129.                 }
  5130.                 else
  5131.                 {
  5132.                     if(dx > dy)
  5133.                     {
  5134.                         diff = -dx / 2;
  5135.  
  5136.                         do
  5137.                         {
  5138.                             xstep++;
  5139.  
  5140.                             if(diff > 0)
  5141.                             {
  5142.                                 ystep++;
  5143.  
  5144.                                 diff = diff + dy - dx;
  5145.                             }
  5146.                             else
  5147.                                 diff += dy;
  5148.  
  5149.                             {
  5150.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5151.  
  5152.                                 if(y1 != last)
  5153.                                     line = &plane[(last = y1) * modulo];
  5154.  
  5155.                                 line[x1 >> 3] |= shift[x1 & 7];
  5156.                             }
  5157.                         }
  5158.                         while(xstep < dx);
  5159.                     }
  5160.                     else
  5161.                     {
  5162.                         if(dx == dy)
  5163.                             diff = 0;
  5164.                         else
  5165.                             diff = dy / 2;
  5166.  
  5167.                         do
  5168.                         {
  5169.                             ystep++;
  5170.  
  5171.                             if(diff > 0)
  5172.                                 diff -= dx;
  5173.                             else
  5174.                             {
  5175.                                 xstep++;
  5176.  
  5177.                                 diff = diff + dy - dx;
  5178.                             }
  5179.  
  5180.                             {
  5181.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5182.  
  5183.                                 if(y1 != last)
  5184.                                     line = &plane[(last = y1) * modulo];
  5185.  
  5186.                                 line[x1 >> 3] |= shift[x1 & 7];
  5187.                             }
  5188.                         }
  5189.                         while(ystep < dy);
  5190.                     }
  5191.                 }
  5192.  
  5193.                 if(!pen)
  5194.                 {
  5195.                     if(y1 != last)
  5196.                         line = &plane[(last = y1) * modulo];
  5197.  
  5198.                     line[x1 >> 3] &= masks[x1 & 7];
  5199.                 }
  5200.             }
  5201.             else
  5202.             {
  5203.                 line[x >> 3] &= masks[x & 7];
  5204.  
  5205.                 xstep = ystep = 0;
  5206.  
  5207.                 if(dy < 0)
  5208.                 {
  5209.                     if(dx > -dy)
  5210.                     {
  5211.                         diff = -dx / 2;
  5212.  
  5213.                         do
  5214.                         {
  5215.                             xstep++;
  5216.  
  5217.                             if(diff > 0)
  5218.                             {
  5219.                                 ystep--;
  5220.  
  5221.                                 diff = diff - dy - dx;
  5222.                             }
  5223.                             else
  5224.                                 diff -= dy;
  5225.  
  5226.                             {
  5227.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5228.  
  5229.                                 if(y1 != last)
  5230.                                     line = &plane[(last = y1) * modulo];
  5231.  
  5232.                                 line[x1 >> 3] &= masks[x1 & 7];
  5233.                             }
  5234.                         }
  5235.                         while(xstep < dx);
  5236.                     }
  5237.                     else
  5238.                     {
  5239.                         if(dx == -dy)
  5240.                             diff = 0;
  5241.                         else
  5242.                             diff = -dy / 2;
  5243.  
  5244.                         do
  5245.                         {
  5246.                             ystep--;
  5247.  
  5248.                             if(diff > 0)
  5249.                                 diff -= dx;
  5250.                             else
  5251.                             {
  5252.                                 xstep++;
  5253.  
  5254.                                 diff = diff - dy - dx;
  5255.                             }
  5256.  
  5257.                             {
  5258.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5259.  
  5260.                                 if(y1 != last)
  5261.                                     line = &plane[(last = y1) * modulo];
  5262.  
  5263.                                 line[x1 >> 3] &= masks[x1 & 7];
  5264.                             }
  5265.                         }
  5266.                         while(ystep > dy);
  5267.                     }
  5268.                 }
  5269.                 else
  5270.                 {
  5271.                     if(dx > dy)
  5272.                     {
  5273.                         diff = -dx / 2;
  5274.  
  5275.                         do
  5276.                         {
  5277.                             xstep++;
  5278.  
  5279.                             if(diff > 0)
  5280.                             {
  5281.                                 ystep++;
  5282.  
  5283.                                 diff = diff + dy - dx;
  5284.                             }
  5285.                             else
  5286.                                 diff += dy;
  5287.  
  5288.                             {
  5289.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5290.  
  5291.                                 if(y1 != last)
  5292.                                     line = &plane[(last = y1) * modulo];
  5293.  
  5294.                                 line[x1 >> 3] &= masks[x1 & 7];
  5295.                             }
  5296.                         }
  5297.                         while(xstep < dx);
  5298.                     }
  5299.                     else
  5300.                     {
  5301.                         if(dx == dy)
  5302.                             diff = 0;
  5303.                         else
  5304.                             diff =  dy / 2;
  5305.  
  5306.                         do
  5307.                         {
  5308.                             ystep++;
  5309.  
  5310.                             if(diff > 0)
  5311.                                 diff -= dx;
  5312.                             else
  5313.                             {
  5314.                                 xstep++;
  5315.  
  5316.                                 diff = diff + dy - dx;
  5317.                             }
  5318.  
  5319.                             {
  5320.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5321.  
  5322.                                 if(y1 != last)
  5323.                                     line = &plane[(last = y1) * modulo];
  5324.  
  5325.                                 line[x1 >> 3] &= masks[x1 & 7];
  5326.                             }
  5327.                         }
  5328.                         while(ystep < dy);
  5329.                     }
  5330.                 }
  5331.  
  5332.                 if(pen)
  5333.                 {
  5334.                     if(y1 != last)
  5335.                         line = &plane[(last = y1) * modulo];
  5336.  
  5337.                     line[x1 >> 3] |= pen;
  5338.                 }
  5339.             }
  5340.         }
  5341.     }
  5342.  
  5343.     return(0);
  5344. }
  5345.